[Checkins] SVN: lovely.relation/trunk/ DataRealtionProperty allows
the annotation of the relation
Juergen Kartnaller
juergen at kartnaller.at
Wed Sep 12 11:19:13 EDT 2007
Log message for revision 79594:
DataRealtionProperty allows the annotation of the relation
Changed:
U lovely.relation/trunk/CHANGES.txt
A lovely.relation/trunk/src/lovely/relation/dataproperty.py
A lovely.relation/trunk/src/lovely/relation/dataproperty.txt
U lovely.relation/trunk/src/lovely/relation/interfaces.py
U lovely.relation/trunk/src/lovely/relation/property.py
U lovely.relation/trunk/src/lovely/relation/tests.py
-=-
Modified: lovely.relation/trunk/CHANGES.txt
===================================================================
--- lovely.relation/trunk/CHANGES.txt 2007-09-12 15:04:34 UTC (rev 79593)
+++ lovely.relation/trunk/CHANGES.txt 2007-09-12 15:19:13 UTC (rev 79594)
@@ -5,6 +5,9 @@
After
=====
+- DataRealtionProperty allows the annotation of the relation
+
+
2007/09/05 1.1.0a1
==================
Added: lovely.relation/trunk/src/lovely/relation/dataproperty.py
===================================================================
--- lovely.relation/trunk/src/lovely/relation/dataproperty.py (rev 0)
+++ lovely.relation/trunk/src/lovely/relation/dataproperty.py 2007-09-12 15:19:13 UTC (rev 79594)
@@ -0,0 +1,104 @@
+##############################################################################
+#
+# Copyright (c) 2007 Lovely Systems and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Relationship Properties
+
+$Id$
+"""
+
+from types import ListType, TupleType
+
+from zope import interface
+
+from zope.annotation.interfaces import IAttributeAnnotatable
+
+from app import O2OStringTypeRelationship
+from property import RelationPropertyOut
+from interfaces import IDataRelationPropertyOut, IDataRelationship
+
+
+class DataRelationship(O2OStringTypeRelationship):
+ interface.implements(IDataRelationship, IAttributeAnnotatable)
+
+ @apply
+ def source():
+ def get(self):
+ if isinstance(self._sources, (ListType, TupleType)):
+ return self._sources[0]
+ return self._sources
+ def set(self, value):
+ self._sources = value
+ return property(get, set)
+
+ @apply
+ def target():
+ def get(self):
+ if isinstance(self._targets, (ListType, TupleType)):
+ return self._targets[0]
+ return self._targets
+ def set(self, value):
+ self._targets = value
+ return property(get, set)
+
+
+class DataRelationPropertyOut(RelationPropertyOut):
+ interface.implements(IDataRelationPropertyOut)
+
+ def __init__(self, manager, name=None, uids=False, relType=None):
+ super(DataRelationPropertyOut, self).__init__(manager,
+ name,
+ uids,
+ relType)
+
+ def new(self, target):
+ return DataRelationship(None, [self._relType], target)
+
+ def __set__(self, inst, value):
+ if self._field.readonly:
+ raise ValueError(self._name, 'field is readonly')
+ if value is None:
+ v = None
+ elif not self._manager.seqOut:
+ if not IDataRelationship.providedBy(value):
+ raise TypeError
+ v = value
+ v.source = inst
+ else:
+ v = value
+ for val in v:
+ if not IDataRelationship.providedBy(val):
+ raise TypeError
+ for val in v:
+ val.source = inst
+ self._manager.setTargetRelations(inst, v, self._relType)
+ if self._ordered:
+ inst.__dict__['_o_' + self._name] = \
+ list(self._manager.tokenizeValues(value, 'relations'))
+
+ def __get__(self, inst, klass):
+ if inst is None:
+ return self
+ tokens = self._manager.getSourceRelationTokens(inst, self._relType)
+ if self._ordered:
+ tokens = self._sort(inst, tokens)
+ if not self._uids:
+ tokens = self._manager.resolveValueTokens(tokens, 'sources')
+ tokens = list(tokens)
+ if self._manager.seqOut:
+ return tokens
+ else:
+ try:
+ return tokens[0]
+ except IndexError:
+ return None
+
Property changes on: lovely.relation/trunk/src/lovely/relation/dataproperty.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: lovely.relation/trunk/src/lovely/relation/dataproperty.txt
===================================================================
--- lovely.relation/trunk/src/lovely/relation/dataproperty.txt (rev 0)
+++ lovely.relation/trunk/src/lovely/relation/dataproperty.txt 2007-09-12 15:19:13 UTC (rev 79594)
@@ -0,0 +1,160 @@
+======================
+Data Realtion Property
+======================
+
+The data relation property allows us to attach data to the relation.
+
+ >>> from zope import schema, interface
+ >>> from zope.schema.interfaces import IObject
+ >>> class IImage(interface.Interface):
+ ... name = schema.TextLine(title=u'Name')
+
+ >>> class Image(object):
+ ... interface.implements(IImage)
+ ... def __init__(self, name):
+ ... self.name = name
+ ... def __repr__(self):
+ ... return '<image %r>' % self.name
+
+ >>> class IChapter(interface.Interface):
+ ... document = schema.Object(IObject, title=u'Document')
+ ... content = schema.Text(title=u'Content')
+
+ >>> class IDocument(interface.Interface):
+ ... teaser = schema.Object(IImage, title=u'Teaser Image')
+ ... chapters = schema.List(title=u"Chapters",
+ ... value_type=schema.Object(IChapter),
+ ... required=False,
+ ... default=[])
+
+ >>> class IDocumentChapterRelation(interface.Interface):
+ ... document = schema.Object(IDocument, title=u'Document')
+
+We need the IntId utility for our relations.
+
+ >>> from zope import component
+ >>> from zope.app.intid.interfaces import IIntIds
+ >>> intids = component.getUtility(IIntIds)
+
+ >>> from lovely.relation.app import O2OStringTypeRelationships
+ >>> from lovely.relation.interfaces import IO2OStringTypeRelationships
+ >>> rels = O2OStringTypeRelationships()
+ >>> component.provideUtility(rels, IO2OStringTypeRelationships)
+
+We setup a relation manager for the document to teaser relation.
+
+ >>> from lovely.relation.property import FieldRelationManager
+ >>> documentTeaser = FieldRelationManager(IDocument['teaser'])
+ >>> documentChapter = FieldRelationManager(
+ ... IDocument['chapters'],
+ ... IDocumentChapterRelation['document'])
+
+And our document class uses a DataRelationProperty to refer to it's teaser.
+
+ >>> from lovely.relation.dataproperty import DataRelationPropertyOut
+ >>> class Document(object):
+ ... interface.implements(IDocument)
+ ... teaser = DataRelationPropertyOut(documentTeaser)
+ ... smallImg = DataRelationPropertyOut(
+ ... documentTeaser, 'Document.smallImg')
+ ... chapters = DataRelationPropertyOut(documentChapter)
+ ... def __init__(self, name):
+ ... self.name = name
+ ... def __repr__(self):
+ ... return '<document %r>' % self.name
+
+ >>> from lovely.relation.property import RelationPropertyIn
+ >>> class Chapter(object):
+ ... interface.implements(IChapter)
+ ... document = RelationPropertyIn(documentChapter)
+ ... def __init__(self, content):
+ ... self.content = content
+ ... def __repr__(self):
+ ... return '<chapter %r>' % self.content
+
+Now we create a document and an image.
+
+ >>> doc1 = Document(u'Doc One')
+ >>> img1 = Image(u'Image One')
+
+To assign the image to the teaser property we need to instanciate a new
+relation. We do this by calling new on the class property.
+
+ >>> rel1 = Document.teaser.new(img1)
+ >>> rel1
+ <DataRelationship None>
+
+At this time the relation is not bound to the source.
+
+ >>> rel1.source is None
+ True
+ >>> rel1.target
+ <image u'Image One'>
+
+We can bind it :
+
+ >>> doc1.teaser = rel1
+ >>> doc1.teaser is rel1
+ True
+ >>> rel1.source
+ <document u'Doc One'>
+
+It is now possible to annotate the teaser reference.
+
+ >>> from zope.annotation.interfaces import IAnnotatable
+ >>> IAnnotatable.providedBy(rel1)
+ True
+
+To be able to do that we need something which can be annotated.
+
+ >>> class IImagePositionParameters(interface.Interface):
+ ... x = schema.Int(title=u'x')
+ ... y = schema.Int(title=u'y')
+
+ >>> from zope import component
+ >>> class ImagePositionParameters(object):
+ ... interface.implements(IImagePositionParameters)
+ ... component.adapts(IAnnotatable)
+ >>> from zope.annotation.factory import factory
+ >>> posFactory = factory(ImagePositionParameters)
+ >>> component.provideAdapter(posFactory)
+
+ >>> params = IImagePositionParameters(rel1)
+ >>> params
+ <ImagePositionParameters ...>
+
+Let's use a second property from the same relation manager but with another
+relation type.
+
+ >>> img2 = Image(u'Image Two')
+ >>> smallImgRel = Document.smallImg.new(img2)
+ >>> smallImgRel
+ <DataRelationship None>
+ >>> doc1.smallImgRel = smallImgRel
+ >>> doc1.smallImgRel is smallImgRel
+ True
+ >>> doc1.teaser is rel1
+ True
+
+
+Use of lists
+------------
+
+ >>> chapter1 = Chapter(u'Chapter One')
+ >>> chapterRel1 = Document.chapters.new(chapter1)
+ >>> chapterRel1
+ <DataRelationship None>
+ >>> doc1.chapters = (chapterRel1, )
+ >>> [c.target for c in doc1.chapters]
+ [<chapter u'Chapter One'>]
+ >>> chapter1.document
+ <document u'Doc One'>
+
+ >>> chapter2 = Chapter(u'Chapter Two')
+ >>> chapterRel2 = Document.chapters.new(chapter2)
+ >>> doc1.chapters = doc1.chapters + [chapterRel2]
+ >>> [c.target for c in doc1.chapters]
+ [<chapter u'Chapter One'>, <chapter u'Chapter Two'>]
+ >>> chapter2.document
+ <document u'Doc One'>
+
Property changes on: lovely.relation/trunk/src/lovely/relation/dataproperty.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: lovely.relation/trunk/src/lovely/relation/interfaces.py
===================================================================
--- lovely.relation/trunk/src/lovely/relation/interfaces.py 2007-09-12 15:04:34 UTC (rev 79593)
+++ lovely.relation/trunk/src/lovely/relation/interfaces.py 2007-09-12 15:19:13 UTC (rev 79594)
@@ -151,3 +151,25 @@
class IO2OStringTypeRelationship(IOneToOneRelationship):
"""A one to one relationship with a string as type"""
+
+
+class IDataRelationship(interface.Interface):
+
+ source = interface.Attribute(
+ """Source pointing in the relationship. Readonly.""")
+
+ target = interface.Attribute(
+ """Target being pointed to in the relationship. Readonly.""")
+
+
+class IDataRelationPropertyOut(interface.Interface):
+ """Extends the relation property to be able to annotate the relation"""
+
+ def new(self, target):
+ """Instantiate a new relation.
+
+ The returned instance implements IDataRelation and must be used for
+ assignement to a data relation property. The relation instance is
+ annotatable to allow data to be added to a relation.
+ """
+
Modified: lovely.relation/trunk/src/lovely/relation/property.py
===================================================================
--- lovely.relation/trunk/src/lovely/relation/property.py 2007-09-12 15:04:34 UTC (rev 79593)
+++ lovely.relation/trunk/src/lovely/relation/property.py 2007-09-12 15:19:13 UTC (rev 79594)
@@ -48,6 +48,9 @@
self.relType=relType
self.utilName = utilName
+ def _instantiateRelation(self, source, relTypes, target):
+ return O2OStringTypeRelationship(source, relTypes, target)
+
@property
def seqIn(self):
return ISequence.providedBy(self.fIn)
@@ -62,28 +65,22 @@
name=self.utilName)
def getSourceTokens(self, target, relType):
- util = self.util
- return util.findSourceTokens(target, relType)
+ return self.util.findSourceTokens(target, relType)
def getTargetTokens(self, source, relType):
- util = self.util
- return util.findTargetTokens(source, relType)
+ return self.util.findTargetTokens(source, relType)
def getSourceRelations(self, obj, relType):
- util = self.util
- return util.findSourceRelationships(obj, relType)
+ return self.util.findSourceRelationships(obj, relType)
def getTargetRelations(self, obj, relType):
- util = self.util
- return util.findTargetRelationships(obj, relType)
+ return self.util.findTargetRelationships(obj, relType)
def getSourceRelationTokens(self, obj, relType):
- util = self.util
- return util.findSourceRelationshipTokens(obj, relType)
+ return self.util.findSourceRelationshipTokens(obj, relType)
def getTargetRelationTokens(self, obj, relType):
- util = self.util
- return util.findTargetRelationshipTokens(obj, relType)
+ return self.util.findTargetRelationshipTokens(obj, relType)
def setTargets(self, source, targets, relType):
util = self.util
@@ -106,14 +103,40 @@
{'sources': sourceToken,
'relations': relType,
'targets': tt})
- self.util.remove(rel.next())
-
+ util.remove(rel.next())
for addT in list(
- util.relationIndex.resolveValueTokens(addTT, 'targets')):
- rel = O2OStringTypeRelationship(source, [relType],
- addT)
- self.util.add(rel)
+ util.relationIndex.resolveValueTokens(addTT, 'targets')):
+ rel = self._instantiateRelation(source, [relType], addT)
+ util.add(rel)
+ def setTargetRelations(self, source, relations, relType):
+ util = self.util
+ if not self.seqOut:
+ relations = [relations]
+ targets = [rel.target for rel in relations]
+ if targets is not None:
+ newTargetTokens = list(util.relationIndex.tokenizeValues(
+ targets, 'targets'))
+ else:
+ newTargetTokens = []
+ sourceToken = util.relationIndex.tokenizeValues([source],
+ 'sources').next()
+ oldTargetTokens = util.findTargetTokens(source, relType)
+ newTT = set(newTargetTokens)
+ oldTT = set(oldTargetTokens)
+ addTT = newTT.difference(oldTT)
+ delTT = oldTT.difference(newTT)
+ for tt in delTT:
+ rel = util.relationIndex.findRelationships(
+ {'sources': sourceToken,
+ 'relations': relType,
+ 'targets': tt})
+ util.remove(rel.next())
+ rels = [(rel.target, rel) for rel in relations]
+ for token, rel in zip(newTargetTokens, relations):
+ if token in addTT:
+ util.add(rel)
+
def setSources(self, target, sources, relType):
util = self.util
if sources is not None:
@@ -140,11 +163,9 @@
for addT in list(
util.relationIndex.resolveValueTokens(addST, 'sources')):
- rel = O2OStringTypeRelationship(addST, [relType],
- target)
+ rel = self._instantiateRelation(addST, [relType], target)
self.util.add(rel)
-
def tokenizeValues(self, values, index):
return self.util.relationIndex.tokenizeValues(values, index)
Modified: lovely.relation/trunk/src/lovely/relation/tests.py
===================================================================
--- lovely.relation/trunk/src/lovely/relation/tests.py 2007-09-12 15:04:34 UTC (rev 79593)
+++ lovely.relation/trunk/src/lovely/relation/tests.py 2007-09-12 15:19:13 UTC (rev 79594)
@@ -58,6 +58,10 @@
setUp=setUp, tearDown=tearDown,
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
),
+ DocFileSuite('dataproperty.txt',
+ setUp=setUp, tearDown=tearDown,
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+ ),
))
if __name__ == '__main__':
More information about the Checkins
mailing list