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"
|
for="loops.interfaces.IResource"
|
||||||
class=".resource.ResourceConfigureView"
|
class=".resource.ResourceConfigureView"
|
||||||
permission="zope.ManageContent">
|
permission="zope.ManageContent">
|
||||||
|
|
||||||
<page
|
<page
|
||||||
name="configure.html"
|
name="configure.html"
|
||||||
template="resource_configure.pt"
|
template="resource_configure.pt"
|
||||||
|
@ -246,6 +246,14 @@
|
||||||
|
|
||||||
</pages>
|
</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 -->
|
<!-- document -->
|
||||||
|
|
||||||
<page
|
<page
|
||||||
|
|
|
@ -301,6 +301,11 @@
|
||||||
name="loops.conceptTypeSource"
|
name="loops.conceptTypeSource"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<vocabulary
|
||||||
|
factory="loops.type.ResourceTypeSourceList"
|
||||||
|
name="loops.resourceTypeSource"
|
||||||
|
/>
|
||||||
|
|
||||||
<vocabulary
|
<vocabulary
|
||||||
factory="loops.type.TypeInterfaceSourceList"
|
factory="loops.type.TypeInterfaceSourceList"
|
||||||
name="loops.TypeInterfaceSource"
|
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 cybertools.relation.registry import DummyRelationRegistry
|
||||||
>>> from zope.app.testing import ztapi
|
>>> from zope.app.testing import ztapi
|
||||||
>>> ztapi.provideUtility(IRelationRegistry, DummyRelationRegistry())
|
>>> 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
|
Now we can setup a simple loops site with its manager objects, using a
|
||||||
loops setup manager:
|
loops setup manager:
|
||||||
|
@ -52,6 +59,12 @@ We also add some example concepts,
|
||||||
u'Zope 3'
|
u'Zope 3'
|
||||||
|
|
||||||
resources,
|
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
|
>>> from loops.resource import Document, MediaAsset
|
||||||
>>> doc1 = Document(u'Zope Info')
|
>>> doc1 = Document(u'Zope Info')
|
||||||
|
@ -82,7 +95,6 @@ interface. The loops framework provides an adapter (LoopsType) for this
|
||||||
purpose:
|
purpose:
|
||||||
|
|
||||||
>>> from cybertools.typology.interfaces import IType
|
>>> from cybertools.typology.interfaces import IType
|
||||||
>>> from loops.interfaces import IConcept
|
|
||||||
>>> from loops.type import ConceptType
|
>>> from loops.type import ConceptType
|
||||||
>>> ztapi.provideAdapter(IConcept, IType, ConceptType)
|
>>> ztapi.provideAdapter(IConcept, IType, ConceptType)
|
||||||
>>> cc1_type = IType(cc1)
|
>>> cc1_type = IType(cc1)
|
||||||
|
@ -148,6 +160,25 @@ lazy properties, one should always get a new adapter:
|
||||||
<class 'loops.concept.Concept'>
|
<class 'loops.concept.Concept'>
|
||||||
|
|
||||||
Now let's have a look at resources.
|
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.interfaces import IResource
|
||||||
>>> from loops.type import ResourceType
|
>>> from loops.type import ResourceType
|
||||||
|
@ -185,10 +216,11 @@ get a type manager from all loops objects, always with the same context:
|
||||||
True
|
True
|
||||||
|
|
||||||
>>> types = typeManager.types
|
>>> types = typeManager.types
|
||||||
>>> sorted((t.token) for t in types)
|
>>> sorted(t.token for t in types)
|
||||||
['.loops/concepts/predicate', '.loops/concepts/topic',
|
['.loops/concepts/file', '.loops/concepts/image', '.loops/concepts/predicate',
|
||||||
'.loops/concepts/type', 'loops.resource.Document',
|
'.loops/concepts/textdocument', '.loops/concepts/topic',
|
||||||
'loops.resource.MediaAsset']
|
'.loops/concepts/type',
|
||||||
|
'loops.resource.Document', 'loops.resource.MediaAsset']
|
||||||
|
|
||||||
>>> typeManager.getType('.loops/concepts/topic') == cc1_type
|
>>> typeManager.getType('.loops/concepts/topic') == cc1_type
|
||||||
True
|
True
|
||||||
|
@ -201,15 +233,14 @@ condition:
|
||||||
['.loops/concepts/predicate', '.loops/concepts/topic', '.loops/concepts/type']
|
['.loops/concepts/predicate', '.loops/concepts/topic', '.loops/concepts/type']
|
||||||
>>> types = typeManager.listTypes(exclude=('concept',))
|
>>> types = typeManager.listTypes(exclude=('concept',))
|
||||||
>>> sorted(t.token for t in types)
|
>>> 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
|
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
|
A type has an optional typeInterface attribute that objects of this type
|
||||||
will be adaptable to. The default for this is None:
|
will be adaptable to. The default for this is None:
|
||||||
|
|
||||||
|
|
|
@ -177,6 +177,29 @@ class IConceptManagerContained(Interface):
|
||||||
|
|
||||||
# resource interfaces
|
# 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):
|
class IResourceSchema(Interface):
|
||||||
|
|
||||||
title = schema.TextLine(
|
title = schema.TextLine(
|
||||||
|
@ -201,6 +224,8 @@ class IResourceSchema(Interface):
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
|
# the next two interfaces are probably obsolete:
|
||||||
|
|
||||||
class IFileSystemResource(Interface):
|
class IFileSystemResource(Interface):
|
||||||
|
|
||||||
fsPath = schema.BytesLine(
|
fsPath = schema.BytesLine(
|
||||||
|
@ -517,6 +542,7 @@ class ITypeConcept(Interface):
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
# viewName = schema.TextLine()
|
# viewName = schema.TextLine()
|
||||||
|
# storage = schema.Choice()
|
||||||
|
|
||||||
|
|
||||||
class IResourceAdapter(Interface):
|
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.registry import getRelations
|
||||||
from cybertools.relation.interfaces import IRelatable
|
from cybertools.relation.interfaces import IRelatable
|
||||||
|
|
||||||
from interfaces import IResource
|
from interfaces import IBaseResource, IResource
|
||||||
from interfaces import IDocument, IDocumentSchema, IDocumentView
|
from interfaces import IDocument, IDocumentSchema, IDocumentView
|
||||||
from interfaces import IMediaAsset, IMediaAssetSchema, IMediaAssetView
|
from interfaces import IMediaAsset, IMediaAssetSchema, IMediaAssetView
|
||||||
from interfaces import IFileSystemResource, IControlledResource
|
from interfaces import IFileSystemResource, IControlledResource
|
||||||
|
@ -55,11 +55,32 @@ _ = MessageFactory('loops')
|
||||||
|
|
||||||
class Resource(Contained, Persistent):
|
class Resource(Contained, Persistent):
|
||||||
|
|
||||||
implements(IResource, IFileSystemResource, IControlledResource,
|
implements(IBaseResource, IResource, IFileSystemResource, IControlledResource,
|
||||||
IResourceManagerContained, IRelatable)
|
IResourceManagerContained, IRelatable)
|
||||||
|
|
||||||
|
proxyInterface = IMediaAssetView
|
||||||
|
|
||||||
_size = _width = _height = 0
|
_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''
|
_title = u''
|
||||||
def getTitle(self): return self._title
|
def getTitle(self): return self._title
|
||||||
def setTitle(self, title): self._title = title
|
def setTitle(self, title): self._title = title
|
||||||
|
@ -167,6 +188,17 @@ class ResourceManager(BTreeContainer):
|
||||||
|
|
||||||
def getViewManager(self):
|
def getViewManager(self):
|
||||||
return self.getLoopsRoot().getViewManager()
|
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):
|
class DocumentWriteFileAdapter(object):
|
||||||
|
|
14
setup.py
14
setup.py
|
@ -28,7 +28,7 @@ from zope import component
|
||||||
from zope.component import adapts
|
from zope.component import adapts
|
||||||
from zope.interface import implements, Interface
|
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.concept import ConceptManager, Concept
|
||||||
from loops.resource import ResourceManager
|
from loops.resource import ResourceManager
|
||||||
from loops.view import ViewManager, Node
|
from loops.view import ViewManager, Node
|
||||||
|
@ -73,8 +73,16 @@ class SetupManager(object):
|
||||||
hasType = self.addObject(conceptManager, Concept, 'hasType', title=u'has Type')
|
hasType = self.addObject(conceptManager, Concept, 'hasType', title=u'has Type')
|
||||||
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')
|
||||||
typeConcept.conceptType = typeConcept
|
file = self.addObject(conceptManager, Concept, 'file', title=u'File')
|
||||||
predicate.conceptType = typeConcept
|
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
|
hasType.conceptType = predicate
|
||||||
standard.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 import schema
|
||||||
from zope.security.proxy import removeSecurityProxy
|
from zope.security.proxy import removeSecurityProxy
|
||||||
from cybertools.typology.type import BaseType, TypeManager
|
from cybertools.typology.type import BaseType, TypeManager
|
||||||
|
from cybertools.typology.interfaces import ITypeManager
|
||||||
from loops.interfaces import ILoopsObject, IConcept, IResource
|
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.concept import Concept
|
||||||
from loops.resource import Resource, Document, MediaAsset
|
from loops.resource import Resource, Document, MediaAsset
|
||||||
|
|
||||||
|
@ -92,7 +94,8 @@ class LoopsType(BaseType):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def typeProvider(self):
|
def typeProvider(self):
|
||||||
return self.context.conceptType
|
# TODO: unify this type attribute naming...
|
||||||
|
return self.context.resourceType
|
||||||
|
|
||||||
|
|
||||||
class LoopsTypeInfo(LoopsType):
|
class LoopsTypeInfo(LoopsType):
|
||||||
|
@ -110,6 +113,10 @@ class ConceptType(LoopsType):
|
||||||
|
|
||||||
adapts(IConcept)
|
adapts(IConcept)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def typeProvider(self):
|
||||||
|
return self.context.conceptType
|
||||||
|
|
||||||
|
|
||||||
class ConceptTypeInfo(LoopsTypeInfo):
|
class ConceptTypeInfo(LoopsTypeInfo):
|
||||||
""" The type info class used by the type manager for listing types.
|
""" The type info class used by the type manager for listing types.
|
||||||
|
@ -233,8 +240,7 @@ class TypeInterfaceSourceList(object):
|
||||||
|
|
||||||
implements(schema.interfaces.IIterableSource)
|
implements(schema.interfaces.IIterableSource)
|
||||||
|
|
||||||
#typeInterfaces = (ITypeConcept, IFile, IImage,)
|
typeInterfaces = (ITypeConcept, IFile, ITextDocument)
|
||||||
typeInterfaces = (ITypeConcept,)
|
|
||||||
|
|
||||||
def __init__(self, context):
|
def __init__(self, context):
|
||||||
self.context = context
|
self.context = context
|
||||||
|
@ -246,6 +252,25 @@ class TypeInterfaceSourceList(object):
|
||||||
return len(self.typeInterfaces)
|
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):
|
class AdapterBase(object):
|
||||||
""" (Mix-in) Class for concept adapters that provide editing of fields
|
""" (Mix-in) Class for concept adapters that provide editing of fields
|
||||||
defined by the type interface.
|
defined by the type interface.
|
||||||
|
|
Loading…
Add table
Reference in a new issue