work in progress: set up dynamic typing for resources
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@1271 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
f2d9bc9af8
commit
04fa445e54
7 changed files with 155 additions and 20 deletions
|
@ -237,7 +237,7 @@
|
|||
for="loops.interfaces.IResource"
|
||||
class=".resource.ResourceConfigureView"
|
||||
permission="zope.ManageContent">
|
||||
|
||||
|
||||
<page
|
||||
name="configure.html"
|
||||
template="resource_configure.pt"
|
||||
|
@ -246,6 +246,14 @@
|
|||
|
||||
</pages>
|
||||
|
||||
<zope:adapter
|
||||
for="loops.interfaces.IResource
|
||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||
provides="zope.interface.Interface"
|
||||
factory="loops.browser.resource.ResourceView"
|
||||
permission="zope.View"
|
||||
/>
|
||||
|
||||
<!-- document -->
|
||||
|
||||
<page
|
||||
|
|
|
@ -301,6 +301,11 @@
|
|||
name="loops.conceptTypeSource"
|
||||
/>
|
||||
|
||||
<vocabulary
|
||||
factory="loops.type.ResourceTypeSourceList"
|
||||
name="loops.resourceTypeSource"
|
||||
/>
|
||||
|
||||
<vocabulary
|
||||
factory="loops.type.TypeInterfaceSourceList"
|
||||
name="loops.TypeInterfaceSource"
|
||||
|
|
51
helpers.txt
51
helpers.txt
|
@ -25,6 +25,13 @@ and provide a relation registry:
|
|||
>>> from cybertools.relation.registry import DummyRelationRegistry
|
||||
>>> from zope.app.testing import ztapi
|
||||
>>> ztapi.provideUtility(IRelationRegistry, DummyRelationRegistry())
|
||||
|
||||
and care for some type adapter machinery:
|
||||
|
||||
>>> from loops.interfaces import IConcept
|
||||
>>> from loops.interfaces import ITypeConcept
|
||||
>>> from loops.type import TypeConcept
|
||||
>>> component.provideAdapter(TypeConcept, (IConcept,), ITypeConcept)
|
||||
|
||||
Now we can setup a simple loops site with its manager objects, using a
|
||||
loops setup manager:
|
||||
|
@ -52,6 +59,12 @@ We also add some example concepts,
|
|||
u'Zope 3'
|
||||
|
||||
resources,
|
||||
|
||||
>>> from loops.resource import Resource
|
||||
>>> file1 = resources['file1'] = Resource(u'A file')
|
||||
>>> file1.resourceType = concepts['file']
|
||||
|
||||
(the use of Document and MediaAsset may get deprecated soon:)
|
||||
|
||||
>>> from loops.resource import Document, MediaAsset
|
||||
>>> doc1 = Document(u'Zope Info')
|
||||
|
@ -82,7 +95,6 @@ interface. The loops framework provides an adapter (LoopsType) for this
|
|||
purpose:
|
||||
|
||||
>>> from cybertools.typology.interfaces import IType
|
||||
>>> from loops.interfaces import IConcept
|
||||
>>> from loops.type import ConceptType
|
||||
>>> ztapi.provideAdapter(IConcept, IType, ConceptType)
|
||||
>>> cc1_type = IType(cc1)
|
||||
|
@ -148,6 +160,25 @@ lazy properties, one should always get a new adapter:
|
|||
<class 'loops.concept.Concept'>
|
||||
|
||||
Now let's have a look at resources.
|
||||
|
||||
>>> from loops.interfaces import IResource
|
||||
>>> from loops.type import LoopsType
|
||||
>>> component.provideAdapter(LoopsType, (IResource,), IType)
|
||||
>>> file1_type = IType(file1)
|
||||
>>> file1_type.title
|
||||
u'File'
|
||||
>>> file1_type.token
|
||||
'.loops/concepts/file'
|
||||
>>> file1_type.tokenForSearch
|
||||
'loops:resource:file'
|
||||
>>> file1_type.qualifiers
|
||||
('resource',)
|
||||
>>> file1_type.defaultContainer
|
||||
<loops.resource.ResourceManager object ...>
|
||||
>>> file1_type.factory
|
||||
<class 'loops.resource.Resource'>
|
||||
|
||||
(The use of Document and MediaAsset will be deprecated soon...)
|
||||
|
||||
>>> from loops.interfaces import IResource
|
||||
>>> from loops.type import ResourceType
|
||||
|
@ -185,10 +216,11 @@ get a type manager from all loops objects, always with the same context:
|
|||
True
|
||||
|
||||
>>> types = typeManager.types
|
||||
>>> sorted((t.token) for t in types)
|
||||
['.loops/concepts/predicate', '.loops/concepts/topic',
|
||||
'.loops/concepts/type', 'loops.resource.Document',
|
||||
'loops.resource.MediaAsset']
|
||||
>>> sorted(t.token for t in types)
|
||||
['.loops/concepts/file', '.loops/concepts/image', '.loops/concepts/predicate',
|
||||
'.loops/concepts/textdocument', '.loops/concepts/topic',
|
||||
'.loops/concepts/type',
|
||||
'loops.resource.Document', 'loops.resource.MediaAsset']
|
||||
|
||||
>>> typeManager.getType('.loops/concepts/topic') == cc1_type
|
||||
True
|
||||
|
@ -201,15 +233,14 @@ condition:
|
|||
['.loops/concepts/predicate', '.loops/concepts/topic', '.loops/concepts/type']
|
||||
>>> types = typeManager.listTypes(exclude=('concept',))
|
||||
>>> sorted(t.token for t in types)
|
||||
['loops.resource.Document', 'loops.resource.MediaAsset']
|
||||
['.loops/concepts/file', '.loops/concepts/image',
|
||||
'.loops/concepts/textdocument', 'loops.resource.Document',
|
||||
'loops.resource.MediaAsset']
|
||||
|
||||
|
||||
Type-based interfaces and adapters
|
||||
----------------------------------
|
||||
|
||||
>>> from loops.interfaces import ITypeConcept
|
||||
>>> from loops.type import TypeConcept
|
||||
>>> ztapi.provideAdapter(IConcept, ITypeConcept, TypeConcept)
|
||||
|
||||
A type has an optional typeInterface attribute that objects of this type
|
||||
will be adaptable to. The default for this is None:
|
||||
|
||||
|
|
|
@ -177,6 +177,29 @@ class IConceptManagerContained(Interface):
|
|||
|
||||
# resource interfaces
|
||||
|
||||
|
||||
class IBaseResource(Interface):
|
||||
""" New base interface for resources. Functionality beyond this simple
|
||||
interface is provided by adapters that are chosen via the
|
||||
resource type's typeInterface.
|
||||
"""
|
||||
|
||||
title = schema.TextLine(
|
||||
title=_(u'Title'),
|
||||
description=_(u'Title of the resource'),
|
||||
default=u'',
|
||||
missing_value=u'',
|
||||
required=False)
|
||||
|
||||
resourceType = schema.Choice(
|
||||
title=_(u'Resource Type'),
|
||||
description=_(u"The type of the resource, specified by a relation to "
|
||||
"a concept of type 'type'."),
|
||||
default=None,
|
||||
source="loops.resourceTypeSource",
|
||||
required=False)
|
||||
|
||||
|
||||
class IResourceSchema(Interface):
|
||||
|
||||
title = schema.TextLine(
|
||||
|
@ -201,6 +224,8 @@ class IResourceSchema(Interface):
|
|||
required=False)
|
||||
|
||||
|
||||
# the next two interfaces are probably obsolete:
|
||||
|
||||
class IFileSystemResource(Interface):
|
||||
|
||||
fsPath = schema.BytesLine(
|
||||
|
@ -517,6 +542,7 @@ class ITypeConcept(Interface):
|
|||
required=False)
|
||||
|
||||
# viewName = schema.TextLine()
|
||||
# storage = schema.Choice()
|
||||
|
||||
|
||||
class IResourceAdapter(Interface):
|
||||
|
|
36
resource.py
36
resource.py
|
@ -40,7 +40,7 @@ from textindexng.content import IndexContentCollector
|
|||
from cybertools.relation.registry import getRelations
|
||||
from cybertools.relation.interfaces import IRelatable
|
||||
|
||||
from interfaces import IResource
|
||||
from interfaces import IBaseResource, IResource
|
||||
from interfaces import IDocument, IDocumentSchema, IDocumentView
|
||||
from interfaces import IMediaAsset, IMediaAssetSchema, IMediaAssetView
|
||||
from interfaces import IFileSystemResource, IControlledResource
|
||||
|
@ -55,11 +55,32 @@ _ = MessageFactory('loops')
|
|||
|
||||
class Resource(Contained, Persistent):
|
||||
|
||||
implements(IResource, IFileSystemResource, IControlledResource,
|
||||
implements(IBaseResource, IResource, IFileSystemResource, IControlledResource,
|
||||
IResourceManagerContained, IRelatable)
|
||||
|
||||
proxyInterface = IMediaAssetView
|
||||
|
||||
_size = _width = _height = 0
|
||||
|
||||
def getResourceType(self):
|
||||
typePred = self.getLoopsRoot().getConceptManager().getTypePredicate()
|
||||
if typePred is None:
|
||||
return None
|
||||
concepts = self.getConcepts([typePred])
|
||||
# TODO (?): check for multiple types (->Error)
|
||||
return concepts and concepts[0] or None
|
||||
def setResourceType(self, concept):
|
||||
current = self.getResourceType()
|
||||
if current != concept:
|
||||
typePred = self.getLoopsRoot().getConceptManager().getTypePredicate()
|
||||
if typePred is None:
|
||||
raise ValueError('No type predicate found for '
|
||||
+ zapi.getName(self))
|
||||
if current is not None:
|
||||
self.deassignConcept(current, [typePred])
|
||||
self.assignConcept(concept, typePred)
|
||||
resourceType = property(getResourceType, setResourceType)
|
||||
|
||||
_title = u''
|
||||
def getTitle(self): return self._title
|
||||
def setTitle(self, title): self._title = title
|
||||
|
@ -167,6 +188,17 @@ class ResourceManager(BTreeContainer):
|
|||
|
||||
def getViewManager(self):
|
||||
return self.getLoopsRoot().getViewManager()
|
||||
|
||||
|
||||
# adapters and similar stuff
|
||||
|
||||
|
||||
class FileAdapter(object):
|
||||
""" A type adapter for providing file functionality for resources.
|
||||
"""
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
|
||||
class DocumentWriteFileAdapter(object):
|
||||
|
|
14
setup.py
14
setup.py
|
@ -28,7 +28,7 @@ from zope import component
|
|||
from zope.component import adapts
|
||||
from zope.interface import implements, Interface
|
||||
|
||||
from loops.interfaces import ILoops
|
||||
from loops.interfaces import ILoops, ITypeConcept, IFile, IImage, ITextDocument
|
||||
from loops.concept import ConceptManager, Concept
|
||||
from loops.resource import ResourceManager
|
||||
from loops.view import ViewManager, Node
|
||||
|
@ -73,8 +73,16 @@ class SetupManager(object):
|
|||
hasType = self.addObject(conceptManager, Concept, 'hasType', title=u'has Type')
|
||||
predicate = self.addObject(conceptManager, Concept, 'predicate', title=u'Predicate')
|
||||
standard = self.addObject(conceptManager, Concept, 'standard', title=u'subobject')
|
||||
typeConcept.conceptType = typeConcept
|
||||
predicate.conceptType = typeConcept
|
||||
file = self.addObject(conceptManager, Concept, 'file', title=u'File')
|
||||
image = self.addObject(conceptManager, Concept, 'image', title=u'Image')
|
||||
textdocument = self.addObject(conceptManager, Concept,
|
||||
'textdocument', title=u'Text Document')
|
||||
for c in (typeConcept, file, image, textdocument, predicate):
|
||||
c.conceptType = typeConcept
|
||||
ITypeConcept(typeConcept).typeInterface = ITypeConcept
|
||||
ITypeConcept(file).typeInterface = IFile
|
||||
ITypeConcept(image).typeInterface = IImage
|
||||
ITypeConcept(textdocument).typeInterface = ITextDocument
|
||||
hasType.conceptType = predicate
|
||||
standard.conceptType = predicate
|
||||
|
||||
|
|
33
type.py
33
type.py
|
@ -30,8 +30,10 @@ from zope.dottedname.resolve import resolve
|
|||
from zope import schema
|
||||
from zope.security.proxy import removeSecurityProxy
|
||||
from cybertools.typology.type import BaseType, TypeManager
|
||||
from cybertools.typology.interfaces import ITypeManager
|
||||
from loops.interfaces import ILoopsObject, IConcept, IResource
|
||||
from loops.interfaces import ITypeConcept, IResourceAdapter, IFile, IImage
|
||||
from loops.interfaces import ITypeConcept
|
||||
from loops.interfaces import IResourceAdapter, IFile, IImage, ITextDocument
|
||||
from loops.concept import Concept
|
||||
from loops.resource import Resource, Document, MediaAsset
|
||||
|
||||
|
@ -92,7 +94,8 @@ class LoopsType(BaseType):
|
|||
|
||||
@Lazy
|
||||
def typeProvider(self):
|
||||
return self.context.conceptType
|
||||
# TODO: unify this type attribute naming...
|
||||
return self.context.resourceType
|
||||
|
||||
|
||||
class LoopsTypeInfo(LoopsType):
|
||||
|
@ -110,6 +113,10 @@ class ConceptType(LoopsType):
|
|||
|
||||
adapts(IConcept)
|
||||
|
||||
@Lazy
|
||||
def typeProvider(self):
|
||||
return self.context.conceptType
|
||||
|
||||
|
||||
class ConceptTypeInfo(LoopsTypeInfo):
|
||||
""" The type info class used by the type manager for listing types.
|
||||
|
@ -233,8 +240,7 @@ class TypeInterfaceSourceList(object):
|
|||
|
||||
implements(schema.interfaces.IIterableSource)
|
||||
|
||||
#typeInterfaces = (ITypeConcept, IFile, IImage,)
|
||||
typeInterfaces = (ITypeConcept,)
|
||||
typeInterfaces = (ITypeConcept, IFile, ITextDocument)
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
@ -246,6 +252,25 @@ class TypeInterfaceSourceList(object):
|
|||
return len(self.typeInterfaces)
|
||||
|
||||
|
||||
class ResourceTypeSourceList(object):
|
||||
|
||||
implements(schema.interfaces.IIterableSource)
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.resourceTypes)
|
||||
|
||||
@Lazy
|
||||
def resourceTypes(self):
|
||||
types = ITypeManager(self.context).listTypes(include=('resource',))
|
||||
return [t.typeProvider for t in types]
|
||||
|
||||
def __len__(self):
|
||||
return len(self.resourceTypes)
|
||||
|
||||
|
||||
class AdapterBase(object):
|
||||
""" (Mix-in) Class for concept adapters that provide editing of fields
|
||||
defined by the type interface.
|
||||
|
|
Loading…
Add table
Reference in a new issue