provide system qualifier for type type and predicate, check it when searching; + some minor refactorings

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1605 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-03-02 10:48:06 +00:00
parent a2932828fb
commit 6e3e08c781
15 changed files with 146 additions and 88 deletions

View file

@ -140,6 +140,13 @@ class BaseView(GenericView):
def value(self):
return self.context
@Lazy
def uniqueId(self):
return util.getUidForObject(self.context)
#return zapi.getUtility(IRelationRegistry).getUniqueIdForObject(self.context)
# type stuff
@Lazy
def type(self):
return IType(self.context)
@ -174,35 +181,47 @@ class BaseView(GenericView):
for o in objs:
yield BaseView(o, request)
# type listings
def listTypes(self, include=None, exclude=None, sortOn='title'):
types = [dict(token=t.token, title=t.title)
for t in ITypeManager(self.context).listTypes(include, exclude)]
if sortOn:
types.sort(key=lambda x: x[sortOn])
return types
def resourceTypes(self):
return util.KeywordVocabulary([(t.token, t.title)
for t in ITypeManager(self.context).listTypes(('resource',))
if t.factory == Resource])
return util.KeywordVocabulary(self.listTypes(('resource',) ('hidden',)))
#if t.factory == Resource]) # ? if necessary -> type.qualifiers
def conceptTypes(self):
return util.KeywordVocabulary([(t.token, t.title)
for t in ITypeManager(self.context).listTypes(('concept',))])
return util.KeywordVocabulary(self.listTypes(('concept',), ('hidden',)))
def listTypesForSearch(self, include=None, exclude=None, sortOn='title'):
types = [dict(token=t.tokenForSearch, title=t.title)
for t in ITypeManager(self.context).listTypes(include, exclude)]
if sortOn:
types.sort(key=lambda x: x[sortOn])
return types
def typesForSearch(self):
general = [('loops:resource:*', 'Any Resource'),
('loops:concept:*', 'Any Concept'),]
return util.KeywordVocabulary(general + sorted([(t.tokenForSearch, t.title)
for t in ITypeManager(self.context).types])
+ [('loops:*', 'Any')])
return util.KeywordVocabulary(general
+ self.listTypesForSearch(exclude=('system', 'hidden',))
+ [('loops:*', 'Any')])
def conceptTypesForSearch(self):
general = [('loops:concept:*', 'Any Concept'),]
return util.KeywordVocabulary(general + [(t.tokenForSearch, t.title)
for t in ITypeManager(self.context).listTypes(('concept',))])
return util.KeywordVocabulary(general
+ self.listTypesForSearch(('concept',), ('system', 'hidden',),))
def resourceTypesForSearch(self):
general = [('loops:resource:*', 'Any Resource'),]
return util.KeywordVocabulary(general + [(t.tokenForSearch, t.title)
for t in ITypeManager(self.context).listTypes(('resource',))])
return util.KeywordVocabulary(general
+ self.listTypesForSearch(('resource',), ('system', 'hidden'),))
@Lazy
def uniqueId(self):
return zapi.getUtility(IRelationRegistry).getUniqueIdForObject(self.context)
# controllling editing
@Lazy
def editable(self):

View file

@ -42,29 +42,31 @@ class AdapterBase(object):
adapts(IConcept)
_attributes = ('context', '__parent__', )
_schemas = list(IConcept)
_adapterAttributes = ('context', '__parent__', )
_contextAttributes = list(IConcept)
def __init__(self, context):
self.context = context # to get the permission stuff right
self.__parent__ = context
self.context = context
self.__parent__ = context # to get the permission stuff right
def __getattr__(self, attr):
self.checkAttr(attr)
return getattr(self.context, '_' + attr, None)
def __setattr__(self, attr, value):
if attr in self._attributes:
if attr in self._adapterAttributes:
object.__setattr__(self, attr, value)
else:
self.checkAttr(attr)
setattr(self.context, '_' + attr, value)
def checkAttr(self, attr):
if attr not in self._schemas:
if attr not in self._contextAttributes:
raise AttributeError(attr)
def __eq__(self, other):
if other is None:
return False
return self.context == other.context
@ -72,7 +74,7 @@ class ResourceAdapterBase(AdapterBase):
adapts(IResource)
_schemas = list(IResourceAdapter)
_contextAttributes = list(IResourceAdapter)
# other adapters

View file

@ -149,10 +149,6 @@ class Concept(Contained, Persistent):
def deassignChild(self, child, predicates=None):
registry = zapi.getUtility(IRelationRegistry)
#relations = []
#for rs in relationships:
# relations.extend(registry.query(first=self, second=concept,
# relationship=rs))
for rel in self.getChildRelations(predicates, child):
registry.unregister(rel)
@ -192,6 +188,7 @@ class ConceptManager(BTreeContainer):
typeConcept = None
typePredicate = None
defaultPredicate = None
predicateType = None
def getLoopsRoot(self):
return zapi.getParent(self)
@ -209,19 +206,27 @@ class ConceptManager(BTreeContainer):
self.defaultPredicate = self['standard']
return self.defaultPredicate
def getPredicateType(self):
if self.predicateType is None:
dp = self.getDefaultPredicate()
self.predicateType = dp.conceptType
return self.predicateType
def getViewManager(self):
return self.getLoopsRoot().getViewManager()
# adapters and similar components
class ConceptSourceList(object):
class xxxConceptSourceList(object):
# seems to be obsolete
implements(schema.interfaces.IIterableSource)
def __init__(self, context):
#self.context = context
self.context = removeSecurityProxy(context)
self.context = context
#self.context = removeSecurityProxy(context)
root = self.context.getLoopsRoot()
self.concepts = root.getConceptManager()

View file

@ -78,7 +78,8 @@
<require
permission="zope.View"
attributes="getTypePredicate getDefaultPredicate getTypeConcept" />
attributes="getTypePredicate getDefaultPredicate getTypeConcept
getPredicateType" />
</class>

View file

@ -130,7 +130,7 @@ So let's check the type of the type object:
>>> type_type.tokenForSearch
'loops:concept:type'
>>> type_type.qualifiers
('concept',)
('concept', 'system')
Now we register another type ('topic') and assign it to cc1:
@ -151,7 +151,7 @@ lazy properties, one should always get a new adapter:
>>> cc1_type.typeProvider == topic
True
>>> topic_type.qualifiers
('concept',)
('concept', 'system')
>>> topic_type.defaultContainer
<loops.concept.ConceptManager object ...>
>>> topic_type.factory

View file

@ -155,23 +155,30 @@ class IConceptView(Interface):
""" Used for accessing a concept via a node's target attribute"""
class IConceptManager(ILoopsObject, IContainer):
#class IConceptManager(ILoopsObject, IContainer):
class IConceptManager(ILoopsObject):
""" A manager/container for concepts.
"""
contains(IConcept)
def getTypeConcept():
""" Return the concept that provides the type object,
i.e. the type of all types.
"""
def getTypePredicate():
""" Return the concept that provides the type predicate.
"""
def getTypeConcept():
""" Return the concept that provides the type object.
"""
def getDefaultPredicate():
""" Return the concept that provides the default (standard) predicate.
"""
def getPredicateType():
""" Return the concept that provides the predicate type object,
i.e. the type of all predicates.
"""
class IConceptManagerContained(Interface):
containers(IConceptManager)

View file

@ -100,7 +100,7 @@ class Topic(AdapterBase, KnowledgeAdapterMixin):
"""
implements(IKnowledgeElement)
_attributes = ('context', '__parent__', 'parent')
_adapterAttributes = ('context', '__parent__', 'parent')
def getParent(self):
parents = self.context.getParents((self.standardPred,))

View file

@ -72,8 +72,8 @@ class Person(AdapterBase, BasePerson):
implements(IPerson)
_attributes = ('context', '__parent__', 'userId', 'phoneNumbers')
_schemas = list(IPerson) + list(IConcept)
_adapterAttributes = ('context', '__parent__', 'userId', 'phoneNumbers')
_contextAttributes = list(IPerson) + list(IConcept)
def getUserId(self):
return getattr(self.context, '_userId', None)
@ -162,8 +162,8 @@ class Address(AdapterBase):
implements(IAddress)
_attributes = ('context', '__parent__', 'lines')
_schemas = list(IAddress) + list(IConcept)
_adapterAttributes = ('context', '__parent__', 'lines')
_contextAttributes = list(IAddress) + list(IConcept)
def getLines(self):
return getattr(self.context, '_lines', [])

View file

@ -39,6 +39,6 @@ class Task(AdapterBase):
implements(ITask)
_attributes = ('context', '__parent__',)
_schemas = list(ITask) + list(IConcept)
_adapterAttributes = ('context', '__parent__',)
_contextAttributes = list(ITask) + list(IConcept)

View file

@ -28,6 +28,7 @@ from zope import traversing
from zope.app.catalog.interfaces import ICatalog
from zope.cachedescriptors.property import Lazy
from cybertools.typology.interfaces import IType
from loops.interfaces import IConcept
from loops.common import AdapterBase
from loops.type import TypeInterfaceSourceList
@ -59,7 +60,7 @@ class BaseQuery(object):
def loopsRoot(self):
return self.context.context.getLoopsRoot()
def queryConcepts(self, title=None, type=None):
def queryConcepts(self, title=None, type=None, **kw):
if type.endswith('*'):
start = type[:-1]
end = start + '\x7f'
@ -71,16 +72,23 @@ class BaseQuery(object):
else:
result = cat.searchResults(loops_type=(start, end))
result = set(r for r in result if r.getLoopsRoot() == self.loopsRoot)
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):
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))
queue = list(self.queryConcepts(title=title, type=type, **kw))
else:
queue = [util.getObjectForUid(uid)]
concepts = []
@ -100,7 +108,7 @@ class BaseQuery(object):
class FullQuery(BaseQuery):
def query(self, text=None, type=None, useTitle=True, useFull=False,
conceptTitle=None, conceptUid=None, conceptType=None):
conceptTitle=None, conceptUid=None, conceptType=None, **kw):
result = set()
rc = self.queryConceptsWithChildren(title=conceptTitle, uid=conceptUid,
type=conceptType)
@ -136,10 +144,10 @@ class ConceptQuery(BaseQuery):
""" Find concepts of type `type` whose title starts with `title`.
"""
def query(self, title=None, type=None):
def query(self, title=None, type=None, **kw):
if title and not title.endswith('*'):
title += '*'
return self.queryConcepts(title=title, type=type)
return self.queryConcepts(title=title, type=type, **kw)
# QueryConcept: concept objects that allow querying the database.
@ -161,7 +169,7 @@ class QueryConcept(AdapterBase):
implements(IQueryConcept)
_schemas = list(IQueryConcept) + list(IConcept)
_contextAttributes = list(IQueryConcept) + list(IConcept)
TypeInterfaceSourceList.typeInterfaces += (IQueryConcept,)

View file

@ -200,10 +200,9 @@ class FileAdapter(ResourceAdapterBase):
"""
implements(IFile)
_schemas = list(IFile) + list(IBaseResource)
# let the adapter handle the data attribute:
_attributes = ResourceAdapterBase._attributes + ('data',)
_contextAttributes = list(IFile) + list(IBaseResource)
_adapterAttributes = ResourceAdapterBase._adapterAttributes + ('data',)
def setData(self, data): self.context.data = data
def getData(self): return self.context.data
@ -251,7 +250,7 @@ class DocumentAdapter(ResourceAdapterBase):
"""
# let the adapter handle the data attribute:
_attributes = ResourceAdapterBase._attributes + ('data',)
_adapterAttributes = ResourceAdapterBase._adapterAttributes + ('data',)
def setData(self, data): self.context._data = data.replace('\r', '')
def getData(self): return self.context._data
@ -263,7 +262,7 @@ class TextDocumentAdapter(DocumentAdapter):
"""
implements(IDocument)
_schemas = list(IDocument) + list(IBaseResource)
_contextAttributes = list(IDocument) + list(IBaseResource)
class NoteAdapter(DocumentAdapter):
@ -271,7 +270,7 @@ class NoteAdapter(DocumentAdapter):
"""
implements(INote)
_schemas = list(INote) + list(IBaseResource)
_contextAttributes = list(INote) + list(IBaseResource)
# other adapters

View file

@ -78,13 +78,13 @@ zcml in real life:
>>> t = searchView.typesForSearch()
>>> len(t)
11
9
>>> t.getTermByToken('loops:resource:*').title
'Any Resource'
>>> t = searchView.conceptTypesForSearch()
>>> len(t)
5
3
>>> t.getTermByToken('loops:concept:*').title
'Any Concept'

View file

@ -77,11 +77,11 @@ class Search(BaseView):
request.response.setHeader('Content-Type', 'text/plain; charset=UTF-8')
title = request.get('searchString', '').replace('(', ' ').replace(')', ' ')
type = request.get('searchType') or 'loops:concept:*'
result = ConceptQuery(self).query(title=title, type=type)
registry = component.getUtility(IRelationRegistry)
result = ConceptQuery(self).query(title=title, type=type, exclude=('system',))
#registry = component.getUtility(IRelationRegistry)
# simple way to provide JSON format:
return str(sorted([[`o.title`[2:-1] + ' (%s)' % `o.conceptType.title`[2:-1],
`registry.getUniqueIdForObject(o)`]
`int(util.getUidForObject(o))`]
for o in result
if o.getLoopsRoot() == self.loopsRoot])).replace('\\\\x', '\\x')
#return str(sorted([[`o.title`[2:-1], `traversing.api.getName(o)`[2:-1]]

57
type.py
View file

@ -22,13 +22,14 @@ Type management stuff.
$Id$
"""
from zope.app import zapi
from zope import component, schema
from zope.component import adapts
from zope.interface import implements
from zope.cachedescriptors.property import Lazy
from zope.dottedname.resolve import resolve
from zope import schema
from zope.security.proxy import removeSecurityProxy
from zope.traversing.api import getName
from cybertools.typology.type import BaseType, TypeManager
from cybertools.typology.interfaces import ITypeManager
from loops.interfaces import ILoopsObject, IConcept, IResource
@ -44,7 +45,8 @@ class LoopsType(BaseType):
adapts(ILoopsObject)
factoryMapping = dict(concept=Concept, resource=Resource, document=Document)
factoryMapping = dict(concept=Concept, resource=Resource)
#document=Document)
containerMapping = dict(concept='concepts', resource='resources')
@Lazy
@ -60,27 +62,31 @@ class LoopsType(BaseType):
@Lazy
def tokenForSearch(self):
tp = self.typeProvider
typeName = tp is None and 'unknown' or str(zapi.getName(tp))
typeName = tp is None and 'unknown' or str(getName(tp))
return ':'.join(('loops', self.qualifiers[0], typeName,))
@Lazy
def typeInterface(self):
adapter = zapi.queryAdapter(self.typeProvider, ITypeConcept)
adapter = component.queryAdapter(self.typeProvider, ITypeConcept)
if adapter is not None:
return removeSecurityProxy(adapter.typeInterface)
else:
conceptType = self.typeProvider
typeConcept = self.root.getConceptManager().getTypeConcept()
if conceptType is typeConcept:
return ITypeConcept
if self.typeProvider is self.typeConcept:
return ITypeConcept # typeConcept always is a type concept
return None
@Lazy
def qualifiers(self):
ti = self.typeInterface
if ti is None or not issubclass(ti, IResourceAdapter):
return ('concept',)
return ('resource',)
qu = ['concept',]
else:
qu = ['resource',]
# check typeProvider for additional qualifiers:
if self.typeProvider in (self.typeConcept, self.predicateType,):
qu.append('system')
# how to set a type to 'hidden'?
return tuple(qu)
@Lazy
def factory(self):
@ -91,10 +97,6 @@ class LoopsType(BaseType):
def defaultContainer(self):
return self.root[self.containerMapping.get(self.qualifiers[0], 'concept')]
@Lazy
def root(self):
return self.context.getLoopsRoot()
@Lazy
def typeProvider(self):
# TODO: unify this type attribute naming...
@ -115,6 +117,20 @@ class LoopsType(BaseType):
result['default'].append(opt)
return result
# general infos
@Lazy
def root(self):
return self.context.getLoopsRoot()
@Lazy
def typeConcept(self):
return self.root.getConceptManager().getTypeConcept()
@Lazy
def predicateType(self):
return self.root.getConceptManager().getPredicateType()
class LoopsTypeInfo(LoopsType):
""" The type info class used by the type manager for listing types.
@ -144,13 +160,10 @@ class ConceptTypeInfo(LoopsTypeInfo):
class ResourceType(LoopsType):
""" The 'old-style' resource type - different classes (Document, MediaAsset)
per type. Will be replaced by new style types that are governed by
per type. Are replaced by new style types that are governed by
type concepts as is already the case for concepts.
"""
#adapts(IResource)
#typeTitles = {'MediaAsset': u'Media Asset'}
typeTitles = {}
typeInterface = None
@ -165,8 +178,6 @@ class ResourceType(LoopsType):
@Lazy
def token(self):
return '.'.join((self.factory.__module__, self.className))
#cn = self.className
#return '/'.join(('.loops/resources', cn.lower(),))
@Lazy
def tokenForSearch(self):
@ -240,7 +251,7 @@ class TypeConcept(AdapterBase):
implements(ITypeConcept)
_schemas = list(ITypeConcept) + list(IConcept)
_contextAttributes = list(ITypeConcept) + list(IConcept)
def getTypeInterface(self):
ti = getattr(self.context, '_typeInterface', None)
@ -255,10 +266,8 @@ class TypeConcept(AdapterBase):
def getOptions(self):
return getattr(self.context, '_options', [])
#return super(TypeConcept, self).options or []
def setOptions(self, value):
self.context._options = value
#super(TypeConcept, self).options = value
options = property(getOptions, setOptions)

12
util.py
View file

@ -36,8 +36,16 @@ _ = MessageFactory('zope') # it's easier not use a special i18n domain...
class KeywordVocabulary(vocabulary.SimpleVocabulary):
def __init__(self, items, *interfaces):
terms = [vocabulary.SimpleTerm(token, token, title)
for token, title in items]
""" ``items`` may be a tuple of (token, title) or a dictionary
with corresponding elements named 'token' and 'title'.
"""
terms = []
for t in items:
if type(t) is dict:
token, title = t['token'], t['title']
else:
token, title = t
terms.append(vocabulary.SimpleTerm(token, token, title))
super(KeywordVocabulary, self).__init__(terms, *interfaces)