move QueryConcept stuff to loops.expert (keeping old query module for backward compatibility); work in progress: child-based queries with actions
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2935 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
c2a16063c5
commit
d1dbe47d57
33 changed files with 471 additions and 87 deletions
|
@ -37,7 +37,7 @@ top-level loops container and a concept manager:
|
|||
>>> #sorted(concepts)
|
||||
>>> #sorted(resources)
|
||||
>>> len(concepts) + len(resources)
|
||||
14
|
||||
13
|
||||
|
||||
>>> loopsRoot = site['loops']
|
||||
|
||||
|
@ -121,7 +121,7 @@ type manager.
|
|||
>>> from loops.concept import ConceptTypeSourceList
|
||||
>>> types = ConceptTypeSourceList(cc1)
|
||||
>>> sorted(t.title for t in types)
|
||||
[u'Customer', u'Domain', u'Predicate', u'Query', u'Topic', u'Type', u'Unknown Type']
|
||||
[u'Customer', u'Domain', u'Predicate', u'Topic', u'Type', u'Unknown Type']
|
||||
|
||||
Using a PredicateSourceList we can retrieve a list of the available
|
||||
predicates.
|
||||
|
@ -197,7 +197,6 @@ types and predicates.
|
|||
[(u'Customer', '.loops/concepts/customer'),
|
||||
(u'Domain', '.loops/concepts/domain'),
|
||||
(u'Predicate', '.loops/concepts/predicate'),
|
||||
(u'Query', '.loops/concepts/query'),
|
||||
(u'Topic', '.loops/concepts/topic'),
|
||||
(u'Type', '.loops/concepts/type'),
|
||||
(u'Unknown Type', '.loops/concepts/unknown')]
|
||||
|
@ -487,7 +486,7 @@ view; these views we have to provide as multi-adapters:
|
|||
>>> view = ConfigureView(m111, TestRequest(form = form))
|
||||
>>> tt = view.targetTypes()
|
||||
>>> len(tt)
|
||||
10
|
||||
9
|
||||
>>> sorted((t.token, t.title) for t in view.targetTypes())[1]
|
||||
('.loops/concepts/domain', u'Domain')
|
||||
>>> view.update()
|
||||
|
@ -580,7 +579,7 @@ is ``NodeView.getUrlForTarget()`` that expects a ConceptView, ResourceView,
|
|||
or ConceptRelationView as its argument.
|
||||
|
||||
>>> view.getUrlForTarget(childRels[0])
|
||||
'http://127.0.0.1/loops/views/m1/m11/m112/.target39'
|
||||
'http://127.0.0.1/loops/views/m1/m11/m112/.target37'
|
||||
|
||||
Actions
|
||||
-------
|
||||
|
|
|
@ -121,9 +121,10 @@
|
|||
tal:define="resources python: list(item.resources())"
|
||||
tal:condition="resources">
|
||||
<h2 i18n:translate="">Resources</h2>
|
||||
<table class="listing">
|
||||
<table class="listing"
|
||||
metal:define-macro="resources">
|
||||
<tr>
|
||||
<th tal:condition="view/showCheckboxes|nothing"> </th>
|
||||
<th tal:condition="item/showCheckboxes|nothing"> </th>
|
||||
<th i18n:translate="">Title</th>
|
||||
<th i18n:translate="">Type</th>
|
||||
<th i18n:translate=""
|
||||
|
@ -138,8 +139,11 @@
|
|||
<tal:item define="class python: repeat['related'].odd() and 'even' or 'odd';
|
||||
description related/description">
|
||||
<tr tal:attributes="class class">
|
||||
<td tal:condition="view/showCheckboxes|nothing"
|
||||
class="checkbox"><input type="checkbox" /></td>
|
||||
<td tal:condition="item/showCheckboxes|nothing"
|
||||
tal:define="uid related/uniqueId"
|
||||
class="checkbox">
|
||||
<input type="checkbox" name="selection:list" checked
|
||||
tal:attributes="value uid;" /></td>
|
||||
<td valign="top">
|
||||
<a href="#"
|
||||
tal:attributes="href string:${view/url}/.target${related/uniqueId};
|
||||
|
|
|
@ -27,7 +27,7 @@ configuration):
|
|||
>>> concepts, resources, views = t.setup()
|
||||
|
||||
>>> len(concepts), len(resources)
|
||||
(21, 0)
|
||||
(20, 0)
|
||||
|
||||
Let's now add an external collection that reads in a set of resources
|
||||
from external files so we have something to work with.
|
||||
|
|
|
@ -34,7 +34,8 @@ from cybertools.meta.interfaces import IOptions
|
|||
from cybertools.meta.namespace import Executor, ExecutionError
|
||||
from cybertools.typology.interfaces import IType
|
||||
from loops.interfaces import ILoops, ILoopsObject
|
||||
from loops.query import IQueryConcept
|
||||
#from loops.query import IQueryConcept
|
||||
from loops.expert.concept import IQueryConcept
|
||||
from loops import util
|
||||
|
||||
|
||||
|
|
|
@ -17,4 +17,8 @@
|
|||
<allow interface="cybertools.meta.interfaces.IOptions" />
|
||||
</zope:class>
|
||||
|
||||
<!-- backward compatibility -->
|
||||
<zope:adapter factory="loops.config.base.QueryOptions" trusted="True"
|
||||
for="loops.query.IQueryConcept" />
|
||||
|
||||
</configure>
|
||||
|
|
|
@ -436,6 +436,7 @@
|
|||
<include package=".compound.blog" />
|
||||
<include package=".config" />
|
||||
<include package=".constraint" />
|
||||
<include package=".expert" />
|
||||
<include package=".external" />
|
||||
<include package=".i18n" />
|
||||
<include package=".integrator" />
|
||||
|
|
|
@ -9,7 +9,7 @@ type(u'note', u'Note', options=u'', typeInterface='loops.interfaces.INote', view
|
|||
type(u'person', u'Person', options=u'', typeInterface='loops.knowledge.interfaces.IPerson', viewName=u'')
|
||||
type(u'predicate', u'Predicate', options=u'', typeInterface=u'', viewName=u'')
|
||||
type(u'process', u'Prozess', options=u'', typeInterface=u'', viewName=u'')
|
||||
type(u'query', u'Query', options=u'', typeInterface='loops.query.IQueryConcept', viewName=u'')
|
||||
type(u'query', u'Query', options=u'', typeInterface='loops.expert.concept.IQueryConcept', viewName=u'')
|
||||
type(u'textdocument', u'Text', options=u'', typeInterface='loops.interfaces.ITextDocument', viewName=u'')
|
||||
type(u'topic', u'Topic', options=u'', typeInterface='loops.knowledge.interfaces.ITopic', viewName=u'')
|
||||
type(u'type', u'Type', options=u'', typeInterface='loops.interfaces.ITypeConcept', viewName=u'')
|
||||
|
|
|
@ -27,7 +27,7 @@ configuration):
|
|||
>>> concepts, resources, views = t.setup()
|
||||
|
||||
>>> len(concepts) + len(resources)
|
||||
32
|
||||
33
|
||||
|
||||
>>> loopsRoot = site['loops']
|
||||
|
||||
|
@ -47,19 +47,19 @@ Type- and text-based queries
|
|||
>>> from loops.expert import query
|
||||
>>> qu = query.Title('ty*')
|
||||
>>> list(qu.apply())
|
||||
[0, 1, 45]
|
||||
[0, 1, 47]
|
||||
|
||||
>>> qu = query.Type('loops:*')
|
||||
>>> len(list(qu.apply()))
|
||||
32
|
||||
33
|
||||
|
||||
>>> qu = query.Type('loops:concept:predicate')
|
||||
>>> len(list(qu.apply()))
|
||||
6
|
||||
7
|
||||
|
||||
>>> qu = query.Type('loops:concept:predicate') & query.Title('t*')
|
||||
>>> list(qu.apply())
|
||||
[1]
|
||||
[1, 43]
|
||||
|
||||
State-based queries
|
||||
-------------------
|
||||
|
@ -99,7 +99,7 @@ they have at least one concept assigned).
|
|||
|
||||
>>> qu = query.State('classification_quality', 'classified')
|
||||
>>> list(qu.apply())
|
||||
[23, 25, 27]
|
||||
[21, 23, 25]
|
||||
|
||||
Using the stateful adapter for a resource we now manually execute the
|
||||
``verify`` transition.
|
||||
|
@ -113,16 +113,16 @@ Now only two resources are still in the ``qualified`` state, the changed
|
|||
one being in the ``verified`` state.
|
||||
|
||||
>>> list(qu.apply())
|
||||
[25, 27]
|
||||
[23, 25]
|
||||
>>> qu = query.State('classification_quality', 'verified')
|
||||
>>> list(qu.apply())
|
||||
[23]
|
||||
[21]
|
||||
|
||||
We may also provide a sequence of states for querying.
|
||||
|
||||
>>> qu = query.State('classification_quality', ('classified', 'verified',))
|
||||
>>> list(qu.apply())
|
||||
[23, 25, 27]
|
||||
[21, 23, 25]
|
||||
|
||||
Relationship-based queries
|
||||
--------------------------
|
||||
|
@ -135,7 +135,7 @@ syntax (that in turn is based on hurry.query).
|
|||
>>> cust1 = concepts['cust1']
|
||||
>>> qu = query.Resources(cust1)
|
||||
>>> list(qu.apply())
|
||||
[23, 27]
|
||||
[21, 25]
|
||||
|
||||
Getting objects
|
||||
---------------
|
||||
|
@ -208,6 +208,15 @@ A query instance consists of
|
|||
>>> #qi.apply()
|
||||
|
||||
|
||||
Query Concepts and Query Views
|
||||
==============================
|
||||
|
||||
>>> from loops.expert.concept import QueryConcept
|
||||
>>> component.provideAdapter(QueryConcept)
|
||||
|
||||
>>> from loops.expert.browser.base import BaseQueryView
|
||||
|
||||
|
||||
Fin de partie
|
||||
=============
|
||||
|
||||
|
|
|
@ -26,8 +26,12 @@ $Id$
|
|||
from zope import interface, component
|
||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope.traversing.api import getName, getParent
|
||||
|
||||
from loops.browser.common import BaseView
|
||||
from cybertools.browser.form import FormController
|
||||
from loops.browser.common import BaseView, concept_macros
|
||||
from loops.browser.concept import ConceptView
|
||||
from loops.browser.resource import ResourceView, ResourceRelationView
|
||||
from loops.common import adapted
|
||||
from loops import util
|
||||
from loops.util import _
|
||||
|
@ -36,11 +40,65 @@ from loops.util import _
|
|||
queryTemplate = ViewPageTemplateFile('query.pt')
|
||||
|
||||
|
||||
#class BaseQueryView(ConceptView):
|
||||
class BaseQueryView(BaseView):
|
||||
|
||||
template = queryTemplate
|
||||
childViewFactory = ResourceRelationView
|
||||
showCheckboxes = True
|
||||
form_action = 'execute_query_action'
|
||||
|
||||
@Lazy
|
||||
def macro(self):
|
||||
return template.macros['query']
|
||||
return self.template.macros['query']
|
||||
|
||||
@property
|
||||
def infos(self):
|
||||
return concept_macros.macros
|
||||
|
||||
@property
|
||||
def listings(self):
|
||||
return concept_macros.macros
|
||||
|
||||
@property
|
||||
def listings(self):
|
||||
return concept_macros.macros
|
||||
|
||||
@Lazy
|
||||
def targetPredicate(self):
|
||||
return self.conceptManager['querytarget']
|
||||
|
||||
@Lazy
|
||||
def defaultPredicate(self):
|
||||
return self.conceptManager.getDefaultPredicate()
|
||||
|
||||
@Lazy
|
||||
def targets(self):
|
||||
return self.context.getChildren([self.targetPredicate])
|
||||
|
||||
def queryInfo(self):
|
||||
targetNames = ', '.join(["'%s'" % t.title for t in self.targets])
|
||||
return _(u'Selection using: $targets',
|
||||
mapping=dict(targets=targetNames))
|
||||
|
||||
def results(self):
|
||||
for t in self.targets:
|
||||
for r in t.getResourceRelations([self.defaultPredicate]):
|
||||
yield self.childViewFactory(r, self.request, contextIsSecond=True)
|
||||
|
||||
|
||||
class ActionExecutor(FormController):
|
||||
|
||||
def update(self):
|
||||
form = self.request.form
|
||||
actions = [k for k in form.keys() if k.startswith('action.')]
|
||||
if actions:
|
||||
uids = form.get('selection', [])
|
||||
action = actions[0]
|
||||
if action == 'action.delete':
|
||||
print '*** delete', uids
|
||||
for uid in uids:
|
||||
obj = util.getObjectForUid(uid)
|
||||
parent = getParent(obj)
|
||||
del parent[getName(obj)]
|
||||
return True
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
i18n_domain="loops">
|
||||
|
||||
<zope:adapter
|
||||
name="query"
|
||||
name="query.html"
|
||||
for="loops.interfaces.IConcept
|
||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||
provides="zope.interface.Interface"
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
<metal:query define-macro="query">
|
||||
<div id="query">
|
||||
<h1 tal:attributes="class string:content-$level;
|
||||
ondblclick item/openEditWindow"
|
||||
tal:content="item/title">
|
||||
Query
|
||||
</h1>
|
||||
<div id="query"
|
||||
tal:define="resources item/results"
|
||||
tal:attributes="class string:content-$level;">
|
||||
<form method="post">
|
||||
<input type="hidden" name="form.action"
|
||||
tal:attributes="value item/form_action" />
|
||||
<metal:infos use-macro="item/infos/concepttitle" />
|
||||
<div tal:content="item/queryInfo" />
|
||||
<metal:listing use-macro="item/listings/resources" /><br />
|
||||
<div class="buttons">
|
||||
<input type="submit" name="action.delete"
|
||||
value="Delete objects" class="submit"
|
||||
onClick="confirm('Do you really want to delete the selected objects?')"
|
||||
i18n:attributes="value" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</metal:query>
|
||||
|
||||
|
|
211
expert/concept.py
Normal file
211
expert/concept.py
Normal file
|
@ -0,0 +1,211 @@
|
|||
#
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Query concepts management stuff.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from BTrees.IOBTree import IOBTree
|
||||
from BTrees.IFBTree import weightedIntersection, weightedUnion, IFBucket
|
||||
from zope import schema, component
|
||||
from zope.interface import Interface, Attribute, implements
|
||||
from zope.app.catalog.interfaces import ICatalog
|
||||
from zope.app.intid.interfaces import IIntIds
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
|
||||
from cybertools.typology.interfaces import IType
|
||||
from loops.common import AdapterBase
|
||||
from loops.interfaces import IConcept, IConceptSchema
|
||||
from loops.security.common import canListObject
|
||||
from loops.type import TypeInterfaceSourceList
|
||||
from loops.versioning.util import getVersion
|
||||
from loops import util
|
||||
from loops.util import _
|
||||
|
||||
|
||||
class ScoredSet(set):
|
||||
|
||||
def __init__(self, data=set(), scores={}):
|
||||
super(ScoredSet, self).__init__(data)
|
||||
self.scores = scores
|
||||
|
||||
def getScore(self, obj):
|
||||
return self.scores.get(obj, -1)
|
||||
|
||||
|
||||
class BaseQuery(object):
|
||||
|
||||
# TODO: replace with proper use of loops.expert.query
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
@Lazy
|
||||
def catalog(self):
|
||||
return component.getUtility(ICatalog)
|
||||
|
||||
@Lazy
|
||||
def loopsRoot(self):
|
||||
return self.context.context.getLoopsRoot()
|
||||
|
||||
def queryConcepts(self, title=None, type=None, **kw):
|
||||
if type.endswith('*'):
|
||||
start = type[:-1]
|
||||
end = start + '\x7f'
|
||||
else:
|
||||
start = end = type
|
||||
cat = self.catalog
|
||||
if title:
|
||||
result = cat.searchResults(loops_type=(start, end), loops_title=title)
|
||||
else:
|
||||
result = cat.searchResults(loops_type=(start, end))
|
||||
result = set(r for r in result if r.getLoopsRoot() == self.loopsRoot
|
||||
and canListObject(r))
|
||||
if 'exclude' in kw:
|
||||
r1 = set()
|
||||
for r in result:
|
||||
qur = IType(r).qualifiers
|
||||
if not [qux for qux in kw['exclude'] if qux in qur]:
|
||||
r1.add(r)
|
||||
result = r1
|
||||
return result
|
||||
|
||||
def queryConceptsWithChildren(self, title=None, type=None, uid=None, **kw):
|
||||
if title: # there are a few characters that the index doesn't like
|
||||
title = title.replace('(', ' ').replace(')', ' ')
|
||||
if not title and not uid and (type is None or '*' in type):
|
||||
return None
|
||||
result = set()
|
||||
if not uid:
|
||||
queue = list(self.queryConcepts(title=title, type=type, **kw))
|
||||
else:
|
||||
queue = [util.getObjectForUid(uid)]
|
||||
concepts = []
|
||||
while queue:
|
||||
c = queue.pop(0)
|
||||
concepts.append(c)
|
||||
for child in c.getChildren():
|
||||
# TODO: check for tree level, use relevance factors, ...
|
||||
if child not in queue and child not in concepts:
|
||||
queue.append(child)
|
||||
for c in concepts:
|
||||
result.add(c)
|
||||
result.update(getVersion(r) for r in c.getResources())
|
||||
return result
|
||||
|
||||
|
||||
class FullQuery(BaseQuery):
|
||||
|
||||
def query(self, text=None, type=None, useTitle=True, useFull=False,
|
||||
conceptTitle=None, conceptUid=None, conceptType=None, **kw):
|
||||
result = set()
|
||||
scores = {}
|
||||
intids = component.getUtility(IIntIds)
|
||||
rc = self.queryConceptsWithChildren(title=conceptTitle, uid=conceptUid,
|
||||
type=conceptType)
|
||||
if not rc and not text and '*' in type: # there should be some sort of selection...
|
||||
return ScoredSet(result, scores)
|
||||
if text or type != 'loops:*': # TODO: this may be highly inefficient!
|
||||
cat = self.catalog
|
||||
if type.endswith('*'):
|
||||
start = type[:-1]
|
||||
end = start + '\x7f'
|
||||
else:
|
||||
start = end = type
|
||||
criteria = {'loops_type': (start, end),}
|
||||
if useFull and text:
|
||||
criteria['loops_text'] = text
|
||||
r1 = cat.apply(criteria) #r1 = set(cat.searchResults(**criteria))
|
||||
else:
|
||||
r1 = IFBucket() #r1 = set()
|
||||
if useTitle and text:
|
||||
if 'loops_text' in criteria:
|
||||
del criteria['loops_text']
|
||||
criteria['loops_title'] = text
|
||||
r2 = cat.apply(criteria) #r2 = set(cat.searchResults(**criteria))
|
||||
else:
|
||||
r2 = IFBucket() #r2 = set()
|
||||
if not r1 and not r2:
|
||||
r1 = cat.apply(criteria) # search only for type
|
||||
x, uids = weightedUnion(r1, r2) #result = r1.union(r2)
|
||||
for r, score in uids.items():
|
||||
obj = intids.getObject(r)
|
||||
result.add(obj)
|
||||
scores[obj] = score
|
||||
if rc is not None:
|
||||
if result:
|
||||
result = result.intersection(rc)
|
||||
else:
|
||||
result = rc
|
||||
result = set(r for r in result
|
||||
if r.getLoopsRoot() == self.loopsRoot
|
||||
and canListObject(r)
|
||||
and getVersion(r) == r)
|
||||
return ScoredSet(result, scores)
|
||||
|
||||
|
||||
class ConceptQuery(BaseQuery):
|
||||
""" Find concepts of type `type` whose title starts with `title`.
|
||||
"""
|
||||
|
||||
def query(self, title=None, type=None, **kw):
|
||||
if title and not title.endswith('*'):
|
||||
title += '*'
|
||||
return self.queryConcepts(title=title, type=type, **kw)
|
||||
|
||||
|
||||
# QueryConcept: concept objects that allow querying the database.
|
||||
|
||||
class IQueryConcept(IConceptSchema):
|
||||
""" The schema for the query type.
|
||||
"""
|
||||
|
||||
viewName = schema.TextLine(
|
||||
title=_(u'Adapter/View name'),
|
||||
description=_(u'The name of the (multi-) adapter (typically a view) '
|
||||
'to be used for the query and for presenting '
|
||||
'the results'),
|
||||
default=u'',
|
||||
required=True)
|
||||
|
||||
options = schema.List(
|
||||
title=_(u'Options'),
|
||||
description=_(u'Additional settings.'),
|
||||
value_type=schema.TextLine(),
|
||||
default=[],
|
||||
required=False)
|
||||
|
||||
|
||||
class QueryConcept(AdapterBase):
|
||||
|
||||
implements(IQueryConcept)
|
||||
|
||||
_contextAttributes = AdapterBase._contextAttributes + ['viewName']
|
||||
_adapterAttributes = AdapterBase._adapterAttributes + ('options',)
|
||||
|
||||
def getOptions(self):
|
||||
return getattr(self.context, '_options', [])
|
||||
def setOptions(self, value):
|
||||
self.context._options = value
|
||||
options = property(getOptions, setOptions)
|
||||
|
||||
|
||||
TypeInterfaceSourceList.typeInterfaces += (IQueryConcept,)
|
||||
|
27
expert/configure.zcml
Normal file
27
expert/configure.zcml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<!-- $Id$ -->
|
||||
|
||||
<configure
|
||||
xmlns="http://namespaces.zope.org/zope"
|
||||
xmlns:browser="http://namespaces.zope.org/browser"
|
||||
i18n_domain="loops">
|
||||
|
||||
<adapter factory="loops.expert.concept.QueryConcept" trusted="True" />
|
||||
<class class="loops.expert.concept.QueryConcept">
|
||||
<require permission="zope.View"
|
||||
interface="loops.expert.concept.IQueryConcept" />
|
||||
<require permission="zope.ManageContent"
|
||||
set_schema="loops.expert.concept.IQueryConcept" />
|
||||
</class>
|
||||
|
||||
<adapter name="execute_query_action"
|
||||
for="loops.browser.node.NodeView
|
||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||
factory="loops.expert.browser.base.ActionExecutor"
|
||||
permission="zope.ManageContent" />
|
||||
|
||||
<adapter factory="loops.expert.setup.SetupManager"
|
||||
name="expert" />
|
||||
|
||||
<include package=".browser" />
|
||||
|
||||
</configure>
|
42
expert/setup.py
Normal file
42
expert/setup.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
#
|
||||
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
"""
|
||||
Automatic setup of a loops site for the expert package.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from loops.concept import Concept
|
||||
from loops.expert.concept import IQueryConcept
|
||||
from loops.setup import SetupManager as BaseSetupManager
|
||||
|
||||
|
||||
class SetupManager(BaseSetupManager):
|
||||
|
||||
def setup(self):
|
||||
concepts = self.context.getConceptManager()
|
||||
type = concepts.getTypeConcept()
|
||||
predicate = concepts['predicate']
|
||||
# type concepts:
|
||||
queryConcept = self.addAndConfigureObject(concepts, Concept, 'query',
|
||||
title=u'Query', conceptType=type,
|
||||
typeInterface=IQueryConcept)
|
||||
# predicates:
|
||||
queryTarget = self.addObject(concepts, Concept, 'querytarget',
|
||||
title=u'is Query Target', conceptType=predicate)
|
|
@ -10,6 +10,7 @@ from zope.app.catalog.interfaces import ICatalog
|
|||
from cybertools.typology.interfaces import IType
|
||||
from loops import util
|
||||
from loops.concept import Concept
|
||||
from loops.expert.setup import SetupManager as ExpertSetupManager
|
||||
from loops.resource import Resource
|
||||
from loops.knowledge.interfaces import IPerson
|
||||
from loops.knowledge.knowledge import Person
|
||||
|
@ -32,6 +33,7 @@ class TestSite(BaseTestSite):
|
|||
component.provideAdapter(Person, provides=IPerson)
|
||||
|
||||
component.provideAdapter(KnowledgeSetupManager, name='knowledge')
|
||||
component.provideAdapter(ExpertSetupManager, name='expert')
|
||||
setup = SetupManager(loopsRoot)
|
||||
concepts, resources, views = setup.setup()
|
||||
|
||||
|
|
16
external/README.txt
vendored
16
external/README.txt
vendored
|
@ -12,12 +12,12 @@ Let's set up a loops site with basic and example concepts and resources.
|
|||
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
|
||||
>>> site = placefulSetUp(True)
|
||||
|
||||
>>> from loops.tests.setup import TestSite
|
||||
>>> from loops.expert.testsetup import TestSite
|
||||
>>> t = TestSite(site)
|
||||
>>> concepts, resources, views = t.setup()
|
||||
>>> loopsRoot = site['loops']
|
||||
>>> len(concepts), len(resources), len(views)
|
||||
(11, 3, 0)
|
||||
(30, 3, 0)
|
||||
|
||||
|
||||
Importing loops Objects
|
||||
|
@ -44,7 +44,7 @@ Creating the corresponding objects
|
|||
>>> loader = Loader(loopsRoot)
|
||||
>>> loader.load(elements)
|
||||
>>> len(concepts), len(resources), len(views)
|
||||
(12, 3, 0)
|
||||
(31, 3, 0)
|
||||
|
||||
>>> from loops.common import adapted
|
||||
>>> adMyquery = adapted(concepts['myquery'])
|
||||
|
@ -118,7 +118,7 @@ Extracting elements
|
|||
>>> extractor = Extractor(loopsRoot, os.path.join(dataDirectory, 'export'))
|
||||
>>> elements = list(extractor.extract())
|
||||
>>> len(elements)
|
||||
20
|
||||
52
|
||||
|
||||
Writing object information to the external storage
|
||||
--------------------------------------------------
|
||||
|
@ -130,13 +130,13 @@ Writing object information to the external storage
|
|||
>>> writer = PyWriter()
|
||||
>>> writer.write(elements, output)
|
||||
>>> print output.getvalue()
|
||||
type(u'customer', u'Customer', options=u'', typeInterface=u'', viewName=u'')...
|
||||
type(u'query', u'Query', options=u'', typeInterface='loops.query.IQueryConcept',
|
||||
type(u'country', u'Country', options=u'', typeInterface=u'', viewName=u'')...
|
||||
type(u'query', u'Query', options=u'', typeInterface='loops.expert.concept.IQueryConcept',
|
||||
viewName=u'')...
|
||||
concept(u'myquery', u'My Query', u'query', options=u'option1\noption2',
|
||||
viewName=u'mystuff.html')...
|
||||
child(u'projects', u'customer', u'standard')...
|
||||
resource(u'doc04.txt', u'Document 4', u'textdocument', contentType='text/restructured')
|
||||
resource(u'doc04.txt', u'Document 4', u'textdocument', contentType='text/restructured')...
|
||||
resourceRelation(u'myquery', u'doc04.txt', u'standard')
|
||||
node('home', u'Home', '', u'menu', body=u'Welcome')
|
||||
node('myquery', u'My Query', 'home', u'page', target=u'concepts/myquery')...
|
||||
|
@ -172,7 +172,7 @@ corresponding extractor adapter.
|
|||
>>> PyWriter().write(extractor.extract(), output)
|
||||
|
||||
>>> print output.getvalue()
|
||||
type(u'customer', u'Customer', options=u'', typeInterface=u'', viewName=u'')...
|
||||
type(u'country', u'Country', options=u'', typeInterface=u'', viewName=u'')...
|
||||
concept(u'myquery', u'My Query', u'query', options=u'option1\noption2',
|
||||
viewName=u'mystuff.html')[
|
||||
annotations(creators=(u'john',))]...
|
||||
|
|
11
helpers.txt
11
helpers.txt
|
@ -226,7 +226,7 @@ get a type manager from all loops objects, always with the same context:
|
|||
>>> types = typeManager.types
|
||||
>>> typeTokens = sorted(t.token for t in types)
|
||||
>>> len(typeTokens)
|
||||
9
|
||||
8
|
||||
|
||||
>>> typeManager.getType('.loops/concepts/topic') == cc1_type
|
||||
True
|
||||
|
@ -237,7 +237,7 @@ condition:
|
|||
>>> types = typeManager.listTypes(include=('concept',))
|
||||
>>> typeTokens = sorted(t.token for t in types)
|
||||
>>> len(typeTokens)
|
||||
6
|
||||
5
|
||||
>>> types = typeManager.listTypes(exclude=('concept',))
|
||||
>>> typeTokens = sorted(t.token for t in types)
|
||||
>>> len(typeTokens)
|
||||
|
@ -313,9 +313,11 @@ We first have to set up the query type, i.e. a type concept associated
|
|||
with the IQueryConcept interface. The query type concept itself has already
|
||||
been provided by the setup, but we have to register a corresponding adapter.
|
||||
|
||||
>>> from loops.query import QueryConcept
|
||||
>>> from loops.expert.concept import IQueryConcept, QueryConcept
|
||||
>>> component.provideAdapter(QueryConcept)
|
||||
>>> query = concepts['query']
|
||||
>>> from loops.setup import addAndConfigureObject
|
||||
>>> query = addAndConfigureObject(concepts, Concept,
|
||||
... 'query', conceptType=typeObject, typeInterface=IQueryConcept)
|
||||
|
||||
Next we need a concept of this type:
|
||||
|
||||
|
@ -423,7 +425,6 @@ Folders
|
|||
structures of their documents in the filesystem to the loops concept
|
||||
map.
|
||||
|
||||
>>> from loops.setup import addAndConfigureObject
|
||||
>>> tFolder = addAndConfigureObject(concepts, Concept, 'folder',
|
||||
... title=u'Folder', conceptType=typeObject)
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ configuration):
|
|||
>>> concepts, resources, views = t.setup()
|
||||
|
||||
>>> len(concepts) + len(resources)
|
||||
18
|
||||
17
|
||||
|
||||
|
||||
External Collections
|
||||
|
|
|
@ -27,7 +27,7 @@ configuration):
|
|||
>>> concepts, resources, views = t.setup()
|
||||
|
||||
>>> len(concepts) + len(resources)
|
||||
14
|
||||
13
|
||||
|
||||
|
||||
Accessing a Directory in the Filesystem
|
||||
|
|
|
@ -745,6 +745,14 @@ class IExternalFile(IFile):
|
|||
missing_value='',
|
||||
required=False)
|
||||
|
||||
externalAddress = schema.BytesLine(
|
||||
title=_(u'External Address'),
|
||||
description=_(u'The full address for accessing the object '
|
||||
'on the external storage, e.g. a filename or path.'),
|
||||
default='',
|
||||
missing_value='',
|
||||
required=False)
|
||||
|
||||
|
||||
class IImage(IResourceAdapter):
|
||||
""" A media asset that may be embedded in a (web) page as an image.
|
||||
|
|
|
@ -18,7 +18,7 @@ ZCML setup):
|
|||
|
||||
>>> from loops.organize.setup import SetupManager
|
||||
>>> component.provideAdapter(SetupManager, name='organize')
|
||||
>>> from loops.tests.setup import TestSite
|
||||
>>> from loops.expert.testsetup import TestSite
|
||||
>>> t = TestSite(site)
|
||||
>>> concepts, resources, views = t.setup()
|
||||
|
||||
|
@ -237,7 +237,7 @@ Automatic security settings on persons
|
|||
|
||||
>>> from zope.traversing.api import getName
|
||||
>>> list(sorted(getName(c) for c in concepts['person'].getChildren()))
|
||||
[u'john', u'martha', u'person.newuser']
|
||||
[u'jim', u'john', u'martha', u'person.newuser']
|
||||
|
||||
Person objects that have a user assigned to them receive this user
|
||||
(principal) as their owner.
|
||||
|
|
|
@ -72,10 +72,10 @@ So we are now ready to query the favorites.
|
|||
|
||||
>>> favs = list(favorites.query(userName=johnCId))
|
||||
>>> favs
|
||||
[<Favorite ['29', 1, '35', '...']: {}>]
|
||||
[<Favorite ['27', 1, '33', '...']: {}>]
|
||||
|
||||
>>> list(favAdapted.list(johnC))
|
||||
['29']
|
||||
['27']
|
||||
|
||||
>>> util.getObjectForUid(favs[0].taskId) is resources['d001.txt']
|
||||
True
|
||||
|
|
|
@ -14,7 +14,7 @@ First we set up a loops site with basic and example concepts and resources.
|
|||
|
||||
>>> from loops.organize.setup import SetupManager
|
||||
>>> component.provideAdapter(SetupManager, name='organize')
|
||||
>>> from loops.tests.setup import TestSite
|
||||
>>> from loops.expert.testsetup import TestSite
|
||||
>>> t = TestSite(site)
|
||||
>>> concepts, resources, views = t.setup()
|
||||
>>> loopsRoot = site['loops']
|
||||
|
@ -40,7 +40,11 @@ making an object statful we'll use an adapter.
|
|||
We may now take a document and adapt it to IStateful so that we may
|
||||
check the document's state and perform transitions to other states.
|
||||
|
||||
>>> doc01 = resources['d001.txt']
|
||||
>>> from loops.resource import Resource
|
||||
>>> from loops.setup import addAndConfigureObject
|
||||
>>> tText = concepts['textdocument']
|
||||
>>> doc01 = resources['doc01.txt'] = addAndConfigureObject(resources,
|
||||
... Resource, 'doc01.txt', conceptType=tText)
|
||||
>>> statefulDoc01 = component.getAdapter(doc01, IStateful,
|
||||
... name='simple_publishing')
|
||||
|
||||
|
@ -88,7 +92,6 @@ later.
|
|||
|
||||
>>> tCustomer = concepts['customer']
|
||||
>>> from loops.concept import Concept
|
||||
>>> from loops.setup import addAndConfigureObject
|
||||
>>> c01 = addAndConfigureObject(concepts, Concept, 'c01', conceptType=tCustomer,
|
||||
... title='im publishing')
|
||||
>>> c02 = addAndConfigureObject(concepts, Concept, 'c02', conceptType=tCustomer,
|
||||
|
|
|
@ -357,7 +357,6 @@ class ExternalFileAdapter(FileAdapter):
|
|||
def getExternalAddress(self):
|
||||
return getattr(self.context, '_externalAddress', self.context.__name__)
|
||||
def setExternalAddress(self, addr):
|
||||
# TODO (?) - use intId as default?
|
||||
self.context._externalAddress = addr
|
||||
externalAddress = property(getExternalAddress, setExternalAddress)
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ ZCML setup):
|
|||
Let's look what setup has provided us with:
|
||||
|
||||
>>> sorted(concepts)
|
||||
[u'domain', u'file', u'hasType', u'note', u'predicate', u'query',
|
||||
[u'domain', u'file', u'hasType', u'note', u'predicate',
|
||||
u'standard', u'textdocument', u'type']
|
||||
|
||||
|
||||
|
|
|
@ -47,8 +47,10 @@ class FileSchemaFactory(SchemaFactory):
|
|||
|
||||
def __call__(self, interface, **kw):
|
||||
schema = super(FileSchemaFactory, self).__call__(interface, **kw)
|
||||
if 'request' in kw and kw['request'].principal.id != 'rootadmin':
|
||||
schema.fields.remove('contentType')
|
||||
if 'request' in kw:
|
||||
principal = kw['request'].principal
|
||||
if not principal or principal.id != 'rootadmin':
|
||||
schema.fields.remove('contentType')
|
||||
return schema
|
||||
|
||||
|
||||
|
|
|
@ -21,13 +21,13 @@ ZCML setup):
|
|||
>>> from loops.type import ConceptType, TypeConcept
|
||||
>>> from loops.interfaces import ITypeConcept
|
||||
>>> from loops.base import Loops
|
||||
>>> from loops.tests.setup import TestSite
|
||||
>>> from loops.expert.testsetup import TestSite
|
||||
>>> t = TestSite(site)
|
||||
>>> concepts, resources, views = t.setup()
|
||||
|
||||
>>> loopsRoot = site['loops']
|
||||
>>> query = concepts['query']
|
||||
>>> topic = concepts['topic'] = Concept(u'Topic')
|
||||
>>> topic = concepts['topic']
|
||||
|
||||
In addition we create a concept that holds the search page and a node
|
||||
(page) that links to this concept:
|
||||
|
@ -66,13 +66,13 @@ zcml in real life:
|
|||
|
||||
>>> t = searchView.typesForSearch()
|
||||
>>> len(t)
|
||||
9
|
||||
14
|
||||
>>> t.getTermByToken('loops:resource:*').title
|
||||
'Any Resource'
|
||||
|
||||
>>> t = searchView.conceptTypesForSearch()
|
||||
>>> len(t)
|
||||
4
|
||||
9
|
||||
>>> t.getTermByToken('loops:concept:*').title
|
||||
'Any Concept'
|
||||
|
||||
|
@ -91,7 +91,7 @@ a controller attribute for the search view.
|
|||
|
||||
>>> searchView.submitReplacing('1.results', '1.search.form', pageView)
|
||||
'submitReplacing("1.results", "1.search.form",
|
||||
"http://127.0.0.1/loops/views/page/.target29/@@searchresults.html");...'
|
||||
"http://127.0.0.1/loops/views/page/.target80/@@searchresults.html");...'
|
||||
|
||||
Basic (text/title) search
|
||||
-------------------------
|
||||
|
@ -177,7 +177,7 @@ of the concepts' titles:
|
|||
>>> request = TestRequest(form=form)
|
||||
>>> view = Search(page, request)
|
||||
>>> view.listConcepts()
|
||||
u"{identifier: 'id', items: [{label: 'Zope (Topic)', name: 'Zope', id: '34'}, {label: 'Zope 2 (Topic)', name: 'Zope 2', id: '37'}, {label: 'Zope 3 (Topic)', name: 'Zope 3', id: '39'}]}"
|
||||
u"{identifier: 'id', items: [{label: 'Zope (Topic)', name: 'Zope', id: '85'}, {label: 'Zope 2 (Topic)', name: 'Zope 2', id: '87'}, {label: 'Zope 3 (Topic)', name: 'Zope 3', id: '89'}]}"
|
||||
|
||||
Preset Concept Types on Search Forms
|
||||
------------------------------------
|
||||
|
@ -193,8 +193,8 @@ Let's start with a new type, the customer type.
|
|||
>>> custType.options
|
||||
[]
|
||||
|
||||
>>> cust1 = concepts['cust1'] = Concept(u'Zope Corporation')
|
||||
>>> cust2 = concepts['cust2'] = Concept(u'cyberconcepts')
|
||||
>>> cust1 = concepts['cust1']
|
||||
>>> cust2 = concepts['cust2']
|
||||
>>> for c in (cust1, cust2):
|
||||
... c.conceptType = customer
|
||||
... catalog.index_doc(int(util.getUidForObject(c)), c)
|
||||
|
@ -219,16 +219,17 @@ and thus include the customer type in the preset search types.
|
|||
|
||||
>>> searchView.conceptsForType('loops:concept:customer')
|
||||
[{'token': 'none', 'title': u'not selected'},
|
||||
{'token': '47', 'title': u'Zope Corporation'},
|
||||
{'token': '49', 'title': u'cyberconcepts'}]
|
||||
{'token': '58', 'title': u'Customer 1'},
|
||||
{'token': '60', 'title': u'Customer 2'},
|
||||
{'token': '62', 'title': u'Customer 3'}]
|
||||
|
||||
Let's use this new search option for querying:
|
||||
|
||||
>>> form = {'search.4.text_selected': u'47'}
|
||||
>>> form = {'search.4.text_selected': u'58'}
|
||||
>>> resultsView = SearchResults(page, TestRequest(form=form))
|
||||
>>> results = list(resultsView.results)
|
||||
>>> results[0].title
|
||||
u'Zope Corporation'
|
||||
u'Customer 1'
|
||||
|
||||
|
||||
Automatic Filtering
|
||||
|
|
|
@ -36,7 +36,8 @@ from cybertools.typology.interfaces import ITypeManager
|
|||
from loops.browser.common import BaseView
|
||||
from loops.browser.node import NodeView
|
||||
from loops.common import adapted
|
||||
from loops.query import ConceptQuery, FullQuery
|
||||
#from loops.query import ConceptQuery, FullQuery
|
||||
from loops.expert.concept import ConceptQuery, FullQuery
|
||||
from loops import util
|
||||
from loops.util import _
|
||||
|
||||
|
|
8
setup.py
8
setup.py
|
@ -35,7 +35,7 @@ from loops.common import adapted
|
|||
from loops.concept import ConceptManager, Concept
|
||||
from loops.interfaces import ILoops, ITypeConcept
|
||||
from loops.interfaces import IFile, IImage, ITextDocument, INote
|
||||
from loops.query import IQueryConcept
|
||||
#from loops.query import IQueryConcept
|
||||
from loops.record import RecordManager
|
||||
from loops.resource import ResourceManager, Resource
|
||||
from loops.view import ViewManager, Node
|
||||
|
@ -82,16 +82,16 @@ class SetupManager(object):
|
|||
predicate = self.addObject(conceptManager, Concept, 'predicate', title=u'Predicate')
|
||||
standard = self.addObject(conceptManager, Concept, 'standard', title=u'subobject')
|
||||
domain = self.addObject(conceptManager, Concept, 'domain', title=u'Domain')
|
||||
query = self.addObject(conceptManager, Concept, 'query', title=u'Query')
|
||||
#query = self.addObject(conceptManager, Concept, 'query', title=u'Query')
|
||||
file = self.addObject(conceptManager, Concept, 'file', title=u'File')
|
||||
textdocument = self.addObject(conceptManager, Concept,
|
||||
'textdocument', title=u'Text')
|
||||
note = self.addObject(conceptManager, Concept, 'note', title=u'Note')
|
||||
for c in (typeConcept, domain, query, note, file, textdocument, predicate):
|
||||
for c in (typeConcept, domain, note, file, textdocument, predicate):
|
||||
c.conceptType = typeConcept
|
||||
notify(ObjectModifiedEvent(c))
|
||||
ITypeConcept(typeConcept).typeInterface = ITypeConcept
|
||||
ITypeConcept(query).typeInterface = IQueryConcept
|
||||
#ITypeConcept(query).typeInterface = IQueryConcept
|
||||
ITypeConcept(file).typeInterface = IFile
|
||||
ITypeConcept(textdocument).typeInterface = ITextDocument
|
||||
ITypeConcept(note).typeInterface = INote
|
||||
|
|
|
@ -39,7 +39,7 @@ In addition to the application site we need a loops system management site.
|
|||
>>> systemRoot = site['loops.system']
|
||||
|
||||
>>> sorted(sysConcepts)
|
||||
[u'domain', u'file', u'hasType', u'job', u'note', u'predicate', u'query',
|
||||
[u'domain', u'file', u'hasType', u'job', u'note', u'predicate',
|
||||
u'standard', u'textdocument', u'type']
|
||||
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ from cybertools.composer.schema.factory import SchemaFactory
|
|||
from cybertools.composer.schema.field import FieldInstance, NumberFieldInstance
|
||||
from cybertools.composer.schema.field import DateFieldInstance, BooleanFieldInstance
|
||||
from cybertools.composer.schema.field import EmailFieldInstance, ListFieldInstance
|
||||
from cybertools.composer.schema.field import FileUploadFieldInstance
|
||||
from cybertools.composer.schema.instance import Instance, Editor
|
||||
from cybertools.relation.tests import IntIdsStub
|
||||
from cybertools.relation.registry import RelationRegistry, IIndexableRelation
|
||||
|
@ -56,8 +57,7 @@ from loops.layout.base import LayoutNode
|
|||
from loops.organize.memberinfo import MemberInfoProvider
|
||||
from loops.organize.stateful.base import StatefulResourceIndexInfo, handleTransition
|
||||
from loops.predicate import Predicate #, MappingAttributeRelation
|
||||
from loops.query import QueryConcept
|
||||
from loops.query import QueryConcept
|
||||
from loops.expert.concept import QueryConcept
|
||||
from loops.resource import Resource, FileAdapter, TextDocumentAdapter
|
||||
from loops.resource import Document, MediaAsset
|
||||
from loops.resource import IndexAttributes as ResourceIndexAttributes
|
||||
|
@ -139,6 +139,7 @@ class TestSite(object):
|
|||
component.provideAdapter(EmailFieldInstance, name='email')
|
||||
component.provideAdapter(BooleanFieldInstance, name='boolean')
|
||||
component.provideAdapter(ListFieldInstance, name='list')
|
||||
component.provideAdapter(FileUploadFieldInstance, name='fileupload')
|
||||
component.provideAdapter(SchemaFactory)
|
||||
component.provideAdapter(ResourceSchemaFactory)
|
||||
component.provideAdapter(FileSchemaFactory)
|
||||
|
|
|
@ -29,7 +29,7 @@ configuration):
|
|||
>>> #sorted(concepts)
|
||||
>>> #sorted(resources)
|
||||
>>> len(concepts) + len(resources)
|
||||
24
|
||||
23
|
||||
|
||||
|
||||
Version Information
|
||||
|
|
|
@ -34,7 +34,7 @@ ZCML setup):
|
|||
Let's look what setup has provided us with:
|
||||
|
||||
>>> len(concepts)
|
||||
19
|
||||
18
|
||||
|
||||
Now let's add a few more concepts:
|
||||
|
||||
|
@ -58,7 +58,7 @@ There are a few standard objects we can retrieve directly:
|
|||
|
||||
>>> defaultPred = xrf.getDefaultPredicate()
|
||||
>>> defaultPred['id'], defaultPred['name']
|
||||
('16', u'standard')
|
||||
('14', u'standard')
|
||||
>>> typePred = xrf.getTypePredicate()
|
||||
>>> typePred['id'], typePred['name']
|
||||
('1', u'hasType')
|
||||
|
@ -71,7 +71,7 @@ note that the 'hasType' predicate is not shown as it should not be
|
|||
applied in an explicit assignment.
|
||||
|
||||
>>> sorted(t['name'] for t in xrf.getConceptTypes())
|
||||
[u'customer', u'domain', u'file', u'note', u'person', u'predicate', u'query',
|
||||
[u'customer', u'domain', u'file', u'note', u'person', u'predicate',
|
||||
u'task', u'textdocument', u'topic', u'type']
|
||||
>>> sorted(t['name'] for t in xrf.getPredicates())
|
||||
[u'depends', u'knows', u'ownedby', u'provides', u'requires', u'standard']
|
||||
|
@ -80,10 +80,10 @@ We can also retrieve a certain object by its id or its name:
|
|||
|
||||
>>> obj2 = xrf.getObjectById('5')
|
||||
>>> obj2['id'], obj2['name']
|
||||
('5', u'query')
|
||||
('5', u'note')
|
||||
>>> textdoc = xrf.getObjectByName(u'textdocument')
|
||||
>>> textdoc['id'], textdoc['name']
|
||||
('11', u'textdocument')
|
||||
('9', u'textdocument')
|
||||
|
||||
All methods that retrieve one object also returns its children and parents:
|
||||
|
||||
|
@ -94,7 +94,7 @@ All methods that retrieve one object also returns its children and parents:
|
|||
u'hasType'
|
||||
>>> sorted(c['name'] for c in ch[0]['objects'])
|
||||
[u'customer', u'domain', u'file', u'note', u'person', u'predicate',
|
||||
u'query', u'task', u'textdocument', u'topic', u'type']
|
||||
u'task', u'textdocument', u'topic', u'type']
|
||||
|
||||
>>> pa = defaultPred['parents']
|
||||
>>> len(pa)
|
||||
|
@ -113,7 +113,7 @@ We can also retrieve children and parents explicitely:
|
|||
u'hasType'
|
||||
>>> sorted(c['name'] for c in ch[0]['objects'])
|
||||
[u'customer', u'domain', u'file', u'note', u'person', u'predicate',
|
||||
u'query', u'task', u'textdocument', u'topic', u'type']
|
||||
u'task', u'textdocument', u'topic', u'type']
|
||||
|
||||
>>> pa = xrf.getParents('7')
|
||||
>>> len(pa)
|
||||
|
@ -172,14 +172,14 @@ Updating the concept map
|
|||
|
||||
>>> topicId = xrf.getObjectByName('topic')['id']
|
||||
>>> xrf.createConcept(topicId, u'zope2', u'Zope 2')
|
||||
{'description': u'', 'title': u'Zope 2', 'type': '24', 'id': '56',
|
||||
{'description': u'', 'title': u'Zope 2', 'type': '22', 'id': '54',
|
||||
'name': u'zope2'}
|
||||
|
||||
The name of the concept is checked by a name chooser; if the corresponding
|
||||
parameter is empty, the name will be generated from the title.
|
||||
|
||||
>>> xrf.createConcept(topicId, u'', u'Python')
|
||||
{'description': u'', 'title': u'Python', 'type': '24', 'id': '58',
|
||||
{'description': u'', 'title': u'Python', 'type': '22', 'id': '56',
|
||||
'name': u'python'}
|
||||
|
||||
If we try to deassign a ``hasType`` relation nothing will happen; a
|
||||
|
|
Loading…
Add table
Reference in a new issue