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:
helmutm 2008-10-23 13:35:23 +00:00
parent c2a16063c5
commit d1dbe47d57
33 changed files with 471 additions and 87 deletions

View file

@ -37,7 +37,7 @@ top-level loops container and a concept manager:
>>> #sorted(concepts) >>> #sorted(concepts)
>>> #sorted(resources) >>> #sorted(resources)
>>> len(concepts) + len(resources) >>> len(concepts) + len(resources)
14 13
>>> loopsRoot = site['loops'] >>> loopsRoot = site['loops']
@ -121,7 +121,7 @@ type manager.
>>> from loops.concept import ConceptTypeSourceList >>> from loops.concept import ConceptTypeSourceList
>>> types = ConceptTypeSourceList(cc1) >>> types = ConceptTypeSourceList(cc1)
>>> sorted(t.title for t in types) >>> 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 Using a PredicateSourceList we can retrieve a list of the available
predicates. predicates.
@ -197,7 +197,6 @@ types and predicates.
[(u'Customer', '.loops/concepts/customer'), [(u'Customer', '.loops/concepts/customer'),
(u'Domain', '.loops/concepts/domain'), (u'Domain', '.loops/concepts/domain'),
(u'Predicate', '.loops/concepts/predicate'), (u'Predicate', '.loops/concepts/predicate'),
(u'Query', '.loops/concepts/query'),
(u'Topic', '.loops/concepts/topic'), (u'Topic', '.loops/concepts/topic'),
(u'Type', '.loops/concepts/type'), (u'Type', '.loops/concepts/type'),
(u'Unknown Type', '.loops/concepts/unknown')] (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)) >>> view = ConfigureView(m111, TestRequest(form = form))
>>> tt = view.targetTypes() >>> tt = view.targetTypes()
>>> len(tt) >>> len(tt)
10 9
>>> sorted((t.token, t.title) for t in view.targetTypes())[1] >>> sorted((t.token, t.title) for t in view.targetTypes())[1]
('.loops/concepts/domain', u'Domain') ('.loops/concepts/domain', u'Domain')
>>> view.update() >>> view.update()
@ -580,7 +579,7 @@ is ``NodeView.getUrlForTarget()`` that expects a ConceptView, ResourceView,
or ConceptRelationView as its argument. or ConceptRelationView as its argument.
>>> view.getUrlForTarget(childRels[0]) >>> 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 Actions
------- -------

View file

@ -121,9 +121,10 @@
tal:define="resources python: list(item.resources())" tal:define="resources python: list(item.resources())"
tal:condition="resources"> tal:condition="resources">
<h2 i18n:translate="">Resources</h2> <h2 i18n:translate="">Resources</h2>
<table class="listing"> <table class="listing"
metal:define-macro="resources">
<tr> <tr>
<th tal:condition="view/showCheckboxes|nothing">&nbsp;</th> <th tal:condition="item/showCheckboxes|nothing">&nbsp;</th>
<th i18n:translate="">Title</th> <th i18n:translate="">Title</th>
<th i18n:translate="">Type</th> <th i18n:translate="">Type</th>
<th i18n:translate="" <th i18n:translate=""
@ -138,8 +139,11 @@
<tal:item define="class python: repeat['related'].odd() and 'even' or 'odd'; <tal:item define="class python: repeat['related'].odd() and 'even' or 'odd';
description related/description"> description related/description">
<tr tal:attributes="class class"> <tr tal:attributes="class class">
<td tal:condition="view/showCheckboxes|nothing" <td tal:condition="item/showCheckboxes|nothing"
class="checkbox"><input type="checkbox" /></td> tal:define="uid related/uniqueId"
class="checkbox">
<input type="checkbox" name="selection:list" checked
tal:attributes="value uid;" /></td>
<td valign="top"> <td valign="top">
<a href="#" <a href="#"
tal:attributes="href string:${view/url}/.target${related/uniqueId}; tal:attributes="href string:${view/url}/.target${related/uniqueId};

View file

@ -27,7 +27,7 @@ configuration):
>>> concepts, resources, views = t.setup() >>> concepts, resources, views = t.setup()
>>> len(concepts), len(resources) >>> len(concepts), len(resources)
(21, 0) (20, 0)
Let's now add an external collection that reads in a set of resources Let's now add an external collection that reads in a set of resources
from external files so we have something to work with. from external files so we have something to work with.

View file

@ -34,7 +34,8 @@ from cybertools.meta.interfaces import IOptions
from cybertools.meta.namespace import Executor, ExecutionError from cybertools.meta.namespace import Executor, ExecutionError
from cybertools.typology.interfaces import IType from cybertools.typology.interfaces import IType
from loops.interfaces import ILoops, ILoopsObject 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 from loops import util

View file

@ -17,4 +17,8 @@
<allow interface="cybertools.meta.interfaces.IOptions" /> <allow interface="cybertools.meta.interfaces.IOptions" />
</zope:class> </zope:class>
<!-- backward compatibility -->
<zope:adapter factory="loops.config.base.QueryOptions" trusted="True"
for="loops.query.IQueryConcept" />
</configure> </configure>

View file

@ -436,6 +436,7 @@
<include package=".compound.blog" /> <include package=".compound.blog" />
<include package=".config" /> <include package=".config" />
<include package=".constraint" /> <include package=".constraint" />
<include package=".expert" />
<include package=".external" /> <include package=".external" />
<include package=".i18n" /> <include package=".i18n" />
<include package=".integrator" /> <include package=".integrator" />

View file

@ -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'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'predicate', u'Predicate', options=u'', typeInterface=u'', viewName=u'')
type(u'process', u'Prozess', 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'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'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'') type(u'type', u'Type', options=u'', typeInterface='loops.interfaces.ITypeConcept', viewName=u'')

View file

@ -27,7 +27,7 @@ configuration):
>>> concepts, resources, views = t.setup() >>> concepts, resources, views = t.setup()
>>> len(concepts) + len(resources) >>> len(concepts) + len(resources)
32 33
>>> loopsRoot = site['loops'] >>> loopsRoot = site['loops']
@ -47,19 +47,19 @@ Type- and text-based queries
>>> from loops.expert import query >>> from loops.expert import query
>>> qu = query.Title('ty*') >>> qu = query.Title('ty*')
>>> list(qu.apply()) >>> list(qu.apply())
[0, 1, 45] [0, 1, 47]
>>> qu = query.Type('loops:*') >>> qu = query.Type('loops:*')
>>> len(list(qu.apply())) >>> len(list(qu.apply()))
32 33
>>> qu = query.Type('loops:concept:predicate') >>> qu = query.Type('loops:concept:predicate')
>>> len(list(qu.apply())) >>> len(list(qu.apply()))
6 7
>>> qu = query.Type('loops:concept:predicate') & query.Title('t*') >>> qu = query.Type('loops:concept:predicate') & query.Title('t*')
>>> list(qu.apply()) >>> list(qu.apply())
[1] [1, 43]
State-based queries State-based queries
------------------- -------------------
@ -99,7 +99,7 @@ they have at least one concept assigned).
>>> qu = query.State('classification_quality', 'classified') >>> qu = query.State('classification_quality', 'classified')
>>> list(qu.apply()) >>> list(qu.apply())
[23, 25, 27] [21, 23, 25]
Using the stateful adapter for a resource we now manually execute the Using the stateful adapter for a resource we now manually execute the
``verify`` transition. ``verify`` transition.
@ -113,16 +113,16 @@ Now only two resources are still in the ``qualified`` state, the changed
one being in the ``verified`` state. one being in the ``verified`` state.
>>> list(qu.apply()) >>> list(qu.apply())
[25, 27] [23, 25]
>>> qu = query.State('classification_quality', 'verified') >>> qu = query.State('classification_quality', 'verified')
>>> list(qu.apply()) >>> list(qu.apply())
[23] [21]
We may also provide a sequence of states for querying. We may also provide a sequence of states for querying.
>>> qu = query.State('classification_quality', ('classified', 'verified',)) >>> qu = query.State('classification_quality', ('classified', 'verified',))
>>> list(qu.apply()) >>> list(qu.apply())
[23, 25, 27] [21, 23, 25]
Relationship-based queries Relationship-based queries
-------------------------- --------------------------
@ -135,7 +135,7 @@ syntax (that in turn is based on hurry.query).
>>> cust1 = concepts['cust1'] >>> cust1 = concepts['cust1']
>>> qu = query.Resources(cust1) >>> qu = query.Resources(cust1)
>>> list(qu.apply()) >>> list(qu.apply())
[23, 27] [21, 25]
Getting objects Getting objects
--------------- ---------------
@ -208,6 +208,15 @@ A query instance consists of
>>> #qi.apply() >>> #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 Fin de partie
============= =============

View file

@ -26,8 +26,12 @@ $Id$
from zope import interface, component from zope import interface, component
from zope.app.pagetemplate import ViewPageTemplateFile from zope.app.pagetemplate import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy 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.common import adapted
from loops import util from loops import util
from loops.util import _ from loops.util import _
@ -36,11 +40,65 @@ from loops.util import _
queryTemplate = ViewPageTemplateFile('query.pt') queryTemplate = ViewPageTemplateFile('query.pt')
#class BaseQueryView(ConceptView):
class BaseQueryView(BaseView): class BaseQueryView(BaseView):
template = queryTemplate template = queryTemplate
childViewFactory = ResourceRelationView
showCheckboxes = True
form_action = 'execute_query_action'
@Lazy @Lazy
def macro(self): 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

View file

@ -6,7 +6,7 @@
i18n_domain="loops"> i18n_domain="loops">
<zope:adapter <zope:adapter
name="query" name="query.html"
for="loops.interfaces.IConcept for="loops.interfaces.IConcept
zope.publisher.interfaces.browser.IBrowserRequest" zope.publisher.interfaces.browser.IBrowserRequest"
provides="zope.interface.Interface" provides="zope.interface.Interface"

View file

@ -1,10 +1,20 @@
<metal:query define-macro="query"> <metal:query define-macro="query">
<div id="query"> <div id="query"
<h1 tal:attributes="class string:content-$level; tal:define="resources item/results"
ondblclick item/openEditWindow" tal:attributes="class string:content-$level;">
tal:content="item/title"> <form method="post">
Query <input type="hidden" name="form.action"
</h1> 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> </div>
</metal:query> </metal:query>

211
expert/concept.py Normal file
View 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
View 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
View 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)

View file

@ -10,6 +10,7 @@ from zope.app.catalog.interfaces import ICatalog
from cybertools.typology.interfaces import IType from cybertools.typology.interfaces import IType
from loops import util from loops import util
from loops.concept import Concept from loops.concept import Concept
from loops.expert.setup import SetupManager as ExpertSetupManager
from loops.resource import Resource from loops.resource import Resource
from loops.knowledge.interfaces import IPerson from loops.knowledge.interfaces import IPerson
from loops.knowledge.knowledge import Person from loops.knowledge.knowledge import Person
@ -32,6 +33,7 @@ class TestSite(BaseTestSite):
component.provideAdapter(Person, provides=IPerson) component.provideAdapter(Person, provides=IPerson)
component.provideAdapter(KnowledgeSetupManager, name='knowledge') component.provideAdapter(KnowledgeSetupManager, name='knowledge')
component.provideAdapter(ExpertSetupManager, name='expert')
setup = SetupManager(loopsRoot) setup = SetupManager(loopsRoot)
concepts, resources, views = setup.setup() concepts, resources, views = setup.setup()

16
external/README.txt vendored
View file

@ -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 >>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
>>> site = placefulSetUp(True) >>> site = placefulSetUp(True)
>>> from loops.tests.setup import TestSite >>> from loops.expert.testsetup import TestSite
>>> t = TestSite(site) >>> t = TestSite(site)
>>> concepts, resources, views = t.setup() >>> concepts, resources, views = t.setup()
>>> loopsRoot = site['loops'] >>> loopsRoot = site['loops']
>>> len(concepts), len(resources), len(views) >>> len(concepts), len(resources), len(views)
(11, 3, 0) (30, 3, 0)
Importing loops Objects Importing loops Objects
@ -44,7 +44,7 @@ Creating the corresponding objects
>>> loader = Loader(loopsRoot) >>> loader = Loader(loopsRoot)
>>> loader.load(elements) >>> loader.load(elements)
>>> len(concepts), len(resources), len(views) >>> len(concepts), len(resources), len(views)
(12, 3, 0) (31, 3, 0)
>>> from loops.common import adapted >>> from loops.common import adapted
>>> adMyquery = adapted(concepts['myquery']) >>> adMyquery = adapted(concepts['myquery'])
@ -118,7 +118,7 @@ Extracting elements
>>> extractor = Extractor(loopsRoot, os.path.join(dataDirectory, 'export')) >>> extractor = Extractor(loopsRoot, os.path.join(dataDirectory, 'export'))
>>> elements = list(extractor.extract()) >>> elements = list(extractor.extract())
>>> len(elements) >>> len(elements)
20 52
Writing object information to the external storage Writing object information to the external storage
-------------------------------------------------- --------------------------------------------------
@ -130,13 +130,13 @@ Writing object information to the external storage
>>> writer = PyWriter() >>> writer = PyWriter()
>>> writer.write(elements, output) >>> writer.write(elements, output)
>>> print output.getvalue() >>> 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'')...
type(u'query', u'Query', options=u'', typeInterface='loops.query.IQueryConcept', type(u'query', u'Query', options=u'', typeInterface='loops.expert.concept.IQueryConcept',
viewName=u'')... viewName=u'')...
concept(u'myquery', u'My Query', u'query', options=u'option1\noption2', concept(u'myquery', u'My Query', u'query', options=u'option1\noption2',
viewName=u'mystuff.html')... viewName=u'mystuff.html')...
child(u'projects', u'customer', u'standard')... 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') resourceRelation(u'myquery', u'doc04.txt', u'standard')
node('home', u'Home', '', u'menu', body=u'Welcome') node('home', u'Home', '', u'menu', body=u'Welcome')
node('myquery', u'My Query', 'home', u'page', target=u'concepts/myquery')... node('myquery', u'My Query', 'home', u'page', target=u'concepts/myquery')...
@ -172,7 +172,7 @@ corresponding extractor adapter.
>>> PyWriter().write(extractor.extract(), output) >>> PyWriter().write(extractor.extract(), output)
>>> print output.getvalue() >>> 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', concept(u'myquery', u'My Query', u'query', options=u'option1\noption2',
viewName=u'mystuff.html')[ viewName=u'mystuff.html')[
annotations(creators=(u'john',))]... annotations(creators=(u'john',))]...

View file

@ -226,7 +226,7 @@ get a type manager from all loops objects, always with the same context:
>>> types = typeManager.types >>> types = typeManager.types
>>> typeTokens = sorted(t.token for t in types) >>> typeTokens = sorted(t.token for t in types)
>>> len(typeTokens) >>> len(typeTokens)
9 8
>>> typeManager.getType('.loops/concepts/topic') == cc1_type >>> typeManager.getType('.loops/concepts/topic') == cc1_type
True True
@ -237,7 +237,7 @@ condition:
>>> types = typeManager.listTypes(include=('concept',)) >>> types = typeManager.listTypes(include=('concept',))
>>> typeTokens = sorted(t.token for t in types) >>> typeTokens = sorted(t.token for t in types)
>>> len(typeTokens) >>> len(typeTokens)
6 5
>>> types = typeManager.listTypes(exclude=('concept',)) >>> types = typeManager.listTypes(exclude=('concept',))
>>> typeTokens = sorted(t.token for t in types) >>> typeTokens = sorted(t.token for t in types)
>>> len(typeTokens) >>> 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 with the IQueryConcept interface. The query type concept itself has already
been provided by the setup, but we have to register a corresponding adapter. 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) >>> 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: Next we need a concept of this type:
@ -423,7 +425,6 @@ Folders
structures of their documents in the filesystem to the loops concept structures of their documents in the filesystem to the loops concept
map. map.
>>> from loops.setup import addAndConfigureObject
>>> tFolder = addAndConfigureObject(concepts, Concept, 'folder', >>> tFolder = addAndConfigureObject(concepts, Concept, 'folder',
... title=u'Folder', conceptType=typeObject) ... title=u'Folder', conceptType=typeObject)

View file

@ -27,7 +27,7 @@ configuration):
>>> concepts, resources, views = t.setup() >>> concepts, resources, views = t.setup()
>>> len(concepts) + len(resources) >>> len(concepts) + len(resources)
18 17
External Collections External Collections

View file

@ -27,7 +27,7 @@ configuration):
>>> concepts, resources, views = t.setup() >>> concepts, resources, views = t.setup()
>>> len(concepts) + len(resources) >>> len(concepts) + len(resources)
14 13
Accessing a Directory in the Filesystem Accessing a Directory in the Filesystem

View file

@ -745,6 +745,14 @@ class IExternalFile(IFile):
missing_value='', missing_value='',
required=False) 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): class IImage(IResourceAdapter):
""" A media asset that may be embedded in a (web) page as an image. """ A media asset that may be embedded in a (web) page as an image.

View file

@ -18,7 +18,7 @@ ZCML setup):
>>> from loops.organize.setup import SetupManager >>> from loops.organize.setup import SetupManager
>>> component.provideAdapter(SetupManager, name='organize') >>> component.provideAdapter(SetupManager, name='organize')
>>> from loops.tests.setup import TestSite >>> from loops.expert.testsetup import TestSite
>>> t = TestSite(site) >>> t = TestSite(site)
>>> concepts, resources, views = t.setup() >>> concepts, resources, views = t.setup()
@ -237,7 +237,7 @@ Automatic security settings on persons
>>> from zope.traversing.api import getName >>> from zope.traversing.api import getName
>>> list(sorted(getName(c) for c in concepts['person'].getChildren())) >>> 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 Person objects that have a user assigned to them receive this user
(principal) as their owner. (principal) as their owner.

View file

@ -72,10 +72,10 @@ So we are now ready to query the favorites.
>>> favs = list(favorites.query(userName=johnCId)) >>> favs = list(favorites.query(userName=johnCId))
>>> favs >>> favs
[<Favorite ['29', 1, '35', '...']: {}>] [<Favorite ['27', 1, '33', '...']: {}>]
>>> list(favAdapted.list(johnC)) >>> list(favAdapted.list(johnC))
['29'] ['27']
>>> util.getObjectForUid(favs[0].taskId) is resources['d001.txt'] >>> util.getObjectForUid(favs[0].taskId) is resources['d001.txt']
True True

View file

@ -14,7 +14,7 @@ First we set up a loops site with basic and example concepts and resources.
>>> from loops.organize.setup import SetupManager >>> from loops.organize.setup import SetupManager
>>> component.provideAdapter(SetupManager, name='organize') >>> component.provideAdapter(SetupManager, name='organize')
>>> from loops.tests.setup import TestSite >>> from loops.expert.testsetup import TestSite
>>> t = TestSite(site) >>> t = TestSite(site)
>>> concepts, resources, views = t.setup() >>> concepts, resources, views = t.setup()
>>> loopsRoot = site['loops'] >>> 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 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. 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, >>> statefulDoc01 = component.getAdapter(doc01, IStateful,
... name='simple_publishing') ... name='simple_publishing')
@ -88,7 +92,6 @@ later.
>>> tCustomer = concepts['customer'] >>> tCustomer = concepts['customer']
>>> from loops.concept import Concept >>> from loops.concept import Concept
>>> from loops.setup import addAndConfigureObject
>>> c01 = addAndConfigureObject(concepts, Concept, 'c01', conceptType=tCustomer, >>> c01 = addAndConfigureObject(concepts, Concept, 'c01', conceptType=tCustomer,
... title='im publishing') ... title='im publishing')
>>> c02 = addAndConfigureObject(concepts, Concept, 'c02', conceptType=tCustomer, >>> c02 = addAndConfigureObject(concepts, Concept, 'c02', conceptType=tCustomer,

View file

@ -357,7 +357,6 @@ class ExternalFileAdapter(FileAdapter):
def getExternalAddress(self): def getExternalAddress(self):
return getattr(self.context, '_externalAddress', self.context.__name__) return getattr(self.context, '_externalAddress', self.context.__name__)
def setExternalAddress(self, addr): def setExternalAddress(self, addr):
# TODO (?) - use intId as default?
self.context._externalAddress = addr self.context._externalAddress = addr
externalAddress = property(getExternalAddress, setExternalAddress) externalAddress = property(getExternalAddress, setExternalAddress)

View file

@ -35,7 +35,7 @@ ZCML setup):
Let's look what setup has provided us with: Let's look what setup has provided us with:
>>> sorted(concepts) >>> 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'] u'standard', u'textdocument', u'type']

View file

@ -47,8 +47,10 @@ class FileSchemaFactory(SchemaFactory):
def __call__(self, interface, **kw): def __call__(self, interface, **kw):
schema = super(FileSchemaFactory, self).__call__(interface, **kw) schema = super(FileSchemaFactory, self).__call__(interface, **kw)
if 'request' in kw and kw['request'].principal.id != 'rootadmin': if 'request' in kw:
schema.fields.remove('contentType') principal = kw['request'].principal
if not principal or principal.id != 'rootadmin':
schema.fields.remove('contentType')
return schema return schema

View file

@ -21,13 +21,13 @@ ZCML setup):
>>> from loops.type import ConceptType, TypeConcept >>> from loops.type import ConceptType, TypeConcept
>>> from loops.interfaces import ITypeConcept >>> from loops.interfaces import ITypeConcept
>>> from loops.base import Loops >>> from loops.base import Loops
>>> from loops.tests.setup import TestSite >>> from loops.expert.testsetup import TestSite
>>> t = TestSite(site) >>> t = TestSite(site)
>>> concepts, resources, views = t.setup() >>> concepts, resources, views = t.setup()
>>> loopsRoot = site['loops'] >>> loopsRoot = site['loops']
>>> query = concepts['query'] >>> 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 In addition we create a concept that holds the search page and a node
(page) that links to this concept: (page) that links to this concept:
@ -66,13 +66,13 @@ zcml in real life:
>>> t = searchView.typesForSearch() >>> t = searchView.typesForSearch()
>>> len(t) >>> len(t)
9 14
>>> t.getTermByToken('loops:resource:*').title >>> t.getTermByToken('loops:resource:*').title
'Any Resource' 'Any Resource'
>>> t = searchView.conceptTypesForSearch() >>> t = searchView.conceptTypesForSearch()
>>> len(t) >>> len(t)
4 9
>>> t.getTermByToken('loops:concept:*').title >>> t.getTermByToken('loops:concept:*').title
'Any Concept' 'Any Concept'
@ -91,7 +91,7 @@ a controller attribute for the search view.
>>> searchView.submitReplacing('1.results', '1.search.form', pageView) >>> searchView.submitReplacing('1.results', '1.search.form', pageView)
'submitReplacing("1.results", "1.search.form", '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 Basic (text/title) search
------------------------- -------------------------
@ -177,7 +177,7 @@ of the concepts' titles:
>>> request = TestRequest(form=form) >>> request = TestRequest(form=form)
>>> view = Search(page, request) >>> view = Search(page, request)
>>> view.listConcepts() >>> 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 Preset Concept Types on Search Forms
------------------------------------ ------------------------------------
@ -193,8 +193,8 @@ Let's start with a new type, the customer type.
>>> custType.options >>> custType.options
[] []
>>> cust1 = concepts['cust1'] = Concept(u'Zope Corporation') >>> cust1 = concepts['cust1']
>>> cust2 = concepts['cust2'] = Concept(u'cyberconcepts') >>> cust2 = concepts['cust2']
>>> for c in (cust1, cust2): >>> for c in (cust1, cust2):
... c.conceptType = customer ... c.conceptType = customer
... catalog.index_doc(int(util.getUidForObject(c)), c) ... 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') >>> searchView.conceptsForType('loops:concept:customer')
[{'token': 'none', 'title': u'not selected'}, [{'token': 'none', 'title': u'not selected'},
{'token': '47', 'title': u'Zope Corporation'}, {'token': '58', 'title': u'Customer 1'},
{'token': '49', 'title': u'cyberconcepts'}] {'token': '60', 'title': u'Customer 2'},
{'token': '62', 'title': u'Customer 3'}]
Let's use this new search option for querying: 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)) >>> resultsView = SearchResults(page, TestRequest(form=form))
>>> results = list(resultsView.results) >>> results = list(resultsView.results)
>>> results[0].title >>> results[0].title
u'Zope Corporation' u'Customer 1'
Automatic Filtering Automatic Filtering

View file

@ -36,7 +36,8 @@ from cybertools.typology.interfaces import ITypeManager
from loops.browser.common import BaseView from loops.browser.common import BaseView
from loops.browser.node import NodeView from loops.browser.node import NodeView
from loops.common import adapted 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 import util
from loops.util import _ from loops.util import _

View file

@ -35,7 +35,7 @@ from loops.common import adapted
from loops.concept import ConceptManager, Concept from loops.concept import ConceptManager, Concept
from loops.interfaces import ILoops, ITypeConcept from loops.interfaces import ILoops, ITypeConcept
from loops.interfaces import IFile, IImage, ITextDocument, INote 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.record import RecordManager
from loops.resource import ResourceManager, Resource from loops.resource import ResourceManager, Resource
from loops.view import ViewManager, Node from loops.view import ViewManager, Node
@ -82,16 +82,16 @@ class SetupManager(object):
predicate = self.addObject(conceptManager, Concept, 'predicate', title=u'Predicate') predicate = self.addObject(conceptManager, Concept, 'predicate', title=u'Predicate')
standard = self.addObject(conceptManager, Concept, 'standard', title=u'subobject') standard = self.addObject(conceptManager, Concept, 'standard', title=u'subobject')
domain = self.addObject(conceptManager, Concept, 'domain', title=u'Domain') 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') file = self.addObject(conceptManager, Concept, 'file', title=u'File')
textdocument = self.addObject(conceptManager, Concept, textdocument = self.addObject(conceptManager, Concept,
'textdocument', title=u'Text') 'textdocument', title=u'Text')
note = self.addObject(conceptManager, Concept, 'note', title=u'Note') 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 c.conceptType = typeConcept
notify(ObjectModifiedEvent(c)) notify(ObjectModifiedEvent(c))
ITypeConcept(typeConcept).typeInterface = ITypeConcept ITypeConcept(typeConcept).typeInterface = ITypeConcept
ITypeConcept(query).typeInterface = IQueryConcept #ITypeConcept(query).typeInterface = IQueryConcept
ITypeConcept(file).typeInterface = IFile ITypeConcept(file).typeInterface = IFile
ITypeConcept(textdocument).typeInterface = ITextDocument ITypeConcept(textdocument).typeInterface = ITextDocument
ITypeConcept(note).typeInterface = INote ITypeConcept(note).typeInterface = INote

View file

@ -39,7 +39,7 @@ In addition to the application site we need a loops system management site.
>>> systemRoot = site['loops.system'] >>> systemRoot = site['loops.system']
>>> sorted(sysConcepts) >>> 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'] u'standard', u'textdocument', u'type']

View file

@ -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 FieldInstance, NumberFieldInstance
from cybertools.composer.schema.field import DateFieldInstance, BooleanFieldInstance from cybertools.composer.schema.field import DateFieldInstance, BooleanFieldInstance
from cybertools.composer.schema.field import EmailFieldInstance, ListFieldInstance 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.composer.schema.instance import Instance, Editor
from cybertools.relation.tests import IntIdsStub from cybertools.relation.tests import IntIdsStub
from cybertools.relation.registry import RelationRegistry, IIndexableRelation 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.memberinfo import MemberInfoProvider
from loops.organize.stateful.base import StatefulResourceIndexInfo, handleTransition from loops.organize.stateful.base import StatefulResourceIndexInfo, handleTransition
from loops.predicate import Predicate #, MappingAttributeRelation from loops.predicate import Predicate #, MappingAttributeRelation
from loops.query import QueryConcept from loops.expert.concept import QueryConcept
from loops.query import QueryConcept
from loops.resource import Resource, FileAdapter, TextDocumentAdapter from loops.resource import Resource, FileAdapter, TextDocumentAdapter
from loops.resource import Document, MediaAsset from loops.resource import Document, MediaAsset
from loops.resource import IndexAttributes as ResourceIndexAttributes from loops.resource import IndexAttributes as ResourceIndexAttributes
@ -139,6 +139,7 @@ class TestSite(object):
component.provideAdapter(EmailFieldInstance, name='email') component.provideAdapter(EmailFieldInstance, name='email')
component.provideAdapter(BooleanFieldInstance, name='boolean') component.provideAdapter(BooleanFieldInstance, name='boolean')
component.provideAdapter(ListFieldInstance, name='list') component.provideAdapter(ListFieldInstance, name='list')
component.provideAdapter(FileUploadFieldInstance, name='fileupload')
component.provideAdapter(SchemaFactory) component.provideAdapter(SchemaFactory)
component.provideAdapter(ResourceSchemaFactory) component.provideAdapter(ResourceSchemaFactory)
component.provideAdapter(FileSchemaFactory) component.provideAdapter(FileSchemaFactory)

View file

@ -29,7 +29,7 @@ configuration):
>>> #sorted(concepts) >>> #sorted(concepts)
>>> #sorted(resources) >>> #sorted(resources)
>>> len(concepts) + len(resources) >>> len(concepts) + len(resources)
24 23
Version Information Version Information

View file

@ -34,7 +34,7 @@ ZCML setup):
Let's look what setup has provided us with: Let's look what setup has provided us with:
>>> len(concepts) >>> len(concepts)
19 18
Now let's add a few more concepts: 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 = xrf.getDefaultPredicate()
>>> defaultPred['id'], defaultPred['name'] >>> defaultPred['id'], defaultPred['name']
('16', u'standard') ('14', u'standard')
>>> typePred = xrf.getTypePredicate() >>> typePred = xrf.getTypePredicate()
>>> typePred['id'], typePred['name'] >>> typePred['id'], typePred['name']
('1', u'hasType') ('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. applied in an explicit assignment.
>>> sorted(t['name'] for t in xrf.getConceptTypes()) >>> 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'] u'task', u'textdocument', u'topic', u'type']
>>> sorted(t['name'] for t in xrf.getPredicates()) >>> sorted(t['name'] for t in xrf.getPredicates())
[u'depends', u'knows', u'ownedby', u'provides', u'requires', u'standard'] [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 = xrf.getObjectById('5')
>>> obj2['id'], obj2['name'] >>> obj2['id'], obj2['name']
('5', u'query') ('5', u'note')
>>> textdoc = xrf.getObjectByName(u'textdocument') >>> textdoc = xrf.getObjectByName(u'textdocument')
>>> textdoc['id'], textdoc['name'] >>> textdoc['id'], textdoc['name']
('11', u'textdocument') ('9', u'textdocument')
All methods that retrieve one object also returns its children and parents: 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' u'hasType'
>>> sorted(c['name'] for c in ch[0]['objects']) >>> sorted(c['name'] for c in ch[0]['objects'])
[u'customer', u'domain', u'file', u'note', u'person', u'predicate', [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'] >>> pa = defaultPred['parents']
>>> len(pa) >>> len(pa)
@ -113,7 +113,7 @@ We can also retrieve children and parents explicitely:
u'hasType' u'hasType'
>>> sorted(c['name'] for c in ch[0]['objects']) >>> sorted(c['name'] for c in ch[0]['objects'])
[u'customer', u'domain', u'file', u'note', u'person', u'predicate', [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') >>> pa = xrf.getParents('7')
>>> len(pa) >>> len(pa)
@ -172,14 +172,14 @@ Updating the concept map
>>> topicId = xrf.getObjectByName('topic')['id'] >>> topicId = xrf.getObjectByName('topic')['id']
>>> xrf.createConcept(topicId, u'zope2', u'Zope 2') >>> 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'} 'name': u'zope2'}
The name of the concept is checked by a name chooser; if the corresponding 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. parameter is empty, the name will be generated from the title.
>>> xrf.createConcept(topicId, u'', u'Python') >>> 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'} 'name': u'python'}
If we try to deassign a ``hasType`` relation nothing will happen; a If we try to deassign a ``hasType`` relation nothing will happen; a