[Checkins] SVN: lovely.relation/trunk/ - extended tests to show behaviour with multiple relations between the same

Juergen Kartnaller juergen at kartnaller.at
Fri Oct 19 05:58:36 EDT 2007


Log message for revision 80932:
  - extended tests to show behaviour with multiple relations between the same
    objects.
  
  - possibility to have multiple relation between the same objects on one
    relation property.
  
  - added DataRelationPropertyIn
  
  

Changed:
  U   lovely.relation/trunk/CHANGES.txt
  U   lovely.relation/trunk/setup.py
  U   lovely.relation/trunk/src/lovely/relation/README.txt
  U   lovely.relation/trunk/src/lovely/relation/dataproperty.py
  U   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/property.txt

-=-
Modified: lovely.relation/trunk/CHANGES.txt
===================================================================
--- lovely.relation/trunk/CHANGES.txt	2007-10-18 19:53:21 UTC (rev 80931)
+++ lovely.relation/trunk/CHANGES.txt	2007-10-19 09:58:34 UTC (rev 80932)
@@ -5,6 +5,17 @@
 After
 =====
 
+2007/10/17 1.1.2a1
+==================
+
+- extended tests to show behaviour with multiple relations between the same
+  objects.
+
+- possibility to have multiple relation between the same objects on one
+  relation property.
+
+- added DataRelationPropertyIn
+
 2007/10/17 1.1.1
 ================
 

Modified: lovely.relation/trunk/setup.py
===================================================================
--- lovely.relation/trunk/setup.py	2007-10-18 19:53:21 UTC (rev 80931)
+++ lovely.relation/trunk/setup.py	2007-10-19 09:58:34 UTC (rev 80932)
@@ -21,7 +21,7 @@
 from setuptools import setup, find_packages, Extension
 
 setup(name='lovely.relation',
-      version='1.1.1',
+      version='1.1.2a1',
       url='http://svn.zope.org/lovely.relation',
       license='ZPL 2.1',
       description='Lovely Relation Packages for Zope3',

Modified: lovely.relation/trunk/src/lovely/relation/README.txt
===================================================================
--- lovely.relation/trunk/src/lovely/relation/README.txt	2007-10-18 19:53:21 UTC (rev 80931)
+++ lovely.relation/trunk/src/lovely/relation/README.txt	2007-10-19 09:58:34 UTC (rev 80932)
@@ -70,7 +70,7 @@
   >>> sourceId is None
   False
 
-Let us add an target to the relationship.
+Let us add a target to the relationship.
 
   >>> target = Target('o1 of s1')
   >>> relationship.targets = [target]
@@ -150,6 +150,40 @@
   [<Source 's1'>, <Source 's2'>]
 
 
+Multiple relations beween two objects
+-------------------------------------
+
+We can have the same relation beween two objects more than once.
+
+  >>> rel1 = Relationship(source, [relType], [])
+  >>> rel1.targets = [target]
+  >>> relations.add(rel1)
+
+We have now three relations for our relType.
+
+  >>> list(intids.getObject(s).sources for s in relations.findRelationTokens(relType))
+  [<Source 's1'>, <Source 's2'>, <Source 's1'>]
+
+But we only see distinct sources.
+
+  >>> [s for s in relations.findSources(target, relType)]
+  [<Source 's1'>, <Source 's2'>]
+
+Removing one relation...
+
+  >>> relations.remove(rel1)
+
+changes the seen relations...
+
+  >>> list(intids.getObject(s).sources for s in relations.findRelationTokens(relType))
+  [<Source 's1'>, <Source 's2'>]
+
+but not the sources
+
+  >>> [s for s in relations.findSources(target, relType)]
+  [<Source 's1'>, <Source 's2'>]
+
+
 Relation Types
 --------------
 

Modified: lovely.relation/trunk/src/lovely/relation/dataproperty.py
===================================================================
--- lovely.relation/trunk/src/lovely/relation/dataproperty.py	2007-10-18 19:53:21 UTC (rev 80931)
+++ lovely.relation/trunk/src/lovely/relation/dataproperty.py	2007-10-19 09:58:34 UTC (rev 80932)
@@ -24,8 +24,12 @@
 from zope.annotation.interfaces import IAttributeAnnotatable
 
 from app import O2OStringTypeRelationship
-from property import RelationPropertyOut
-from interfaces import IDataRelationPropertyOut, IDataRelationship
+from property import RelationPropertyOut, RelationPropertyIn
+from interfaces import (
+        IDataRelationPropertyOut,
+        IDataRelationPropertyIn,
+        IDataRelationship,
+        )
 
 
 class DataRelationship(O2OStringTypeRelationship):
@@ -106,3 +110,61 @@
             except IndexError:
                 return None
 
+
+class DataRelationPropertyIn(RelationPropertyIn):
+    interface.implements(IDataRelationPropertyIn)
+
+    def new(self, target):
+        return DataRelationship(source, self)
+
+    def __set__(self, inst, value):
+        if self._field.readonly:
+            raise ValueError(self._name, 'field is readonly')
+        value = removeAllProxies(value)
+        if value is None:
+            v = None
+        elif not self._manager.seqIn:
+            if not IDataRelationship.providedBy(value):
+                raise TypeError
+            if value.target is None:
+                raise ValueError('source for data relation must not be None')
+            v = value
+            v.target = inst
+            if v.relations == []:
+                v.relations = [self._relType]
+        else:
+            v = [removeAllProxies(v) for v in value]
+            for val in v:
+                if not IDataRelationship.providedBy(val):
+                    raise TypeError('%s'% val)
+                if val.target is None:
+                    raise ValueError('target for data relation must not be None')
+            for val in v:
+                val.target = inst
+                if val.relations == []:
+                    val.relations = [self._relType]
+        self._manager.setSourceRelations(inst, v, self._relType)
+        if self._ordered:
+            if v is not None:
+                tokens = list(self._manager.tokenizeValues(v, 'targets'))
+            else:
+                tokens = []
+            inst.__dict__['_o_' + self._name] = tokens
+
+    def __get__(self, inst, klass):
+        if inst is None:
+            return self
+        tokens = self._manager.getTargetRelationTokens(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.seqIn:
+            return tokens
+        else:
+            try:
+                return tokens[0]
+            except IndexError:
+                return None
+

Modified: lovely.relation/trunk/src/lovely/relation/dataproperty.txt
===================================================================
--- lovely.relation/trunk/src/lovely/relation/dataproperty.txt	2007-10-18 19:53:21 UTC (rev 80931)
+++ lovely.relation/trunk/src/lovely/relation/dataproperty.txt	2007-10-19 09:58:34 UTC (rev 80932)
@@ -63,10 +63,10 @@
   ...     def __repr__(self):
   ...         return '<document %r>' % self.name
 
-  >>> from lovely.relation.property import RelationPropertyIn
+  >>> from lovely.relation.dataproperty import DataRelationPropertyIn
   >>> class Chapter(object):
   ...     interface.implements(IChapter)
-  ...     document = RelationPropertyIn(documentChapter)
+  ...     document = DataRelationPropertyIn(documentChapter)
   ...     def __init__(self, content):
   ...         self.content = content
   ...     def __repr__(self):
@@ -168,7 +168,7 @@
 
   >>> img2 = Image(u'Image Two')
 
-This time we do not use new but instantiate the data relation manually.
+This time we do not use "new" but instantiate the data relation manually.
 
   >>> smallImgRel = DataRelationship(img2)
   >>> smallImgRel
@@ -176,11 +176,11 @@
   >>> doc1.smallImgRel = smallImgRel
   >>> doc1.smallImgRel is smallImgRel
   True
-  >>> doc1.teaser is rel1
-  True
   >>> smallImgRel
   <DataRelationship None, <image u'Image Two'>, []>
 
+  >>> doc1.teaser is manualRel
+  True
   >>> doc1.teaser = None
   >>> doc1.teaser is None
   True
@@ -198,7 +198,7 @@
   >>> doc1.chapters = (chapterRel1, )
   >>> [c.target for c in doc1.chapters]
   [<chapter u'Chapter One'>]
-  >>> chapter1.document
+  >>> chapter1.document.source
   <document u'Doc One'>
 
   >>> chapter2 = Chapter(u'Chapter Two')
@@ -206,9 +206,19 @@
   >>> doc1.chapters = doc1.chapters + [chapterRel2]
   >>> [c.target for c in doc1.chapters]
   [<chapter u'Chapter One'>, <chapter u'Chapter Two'>]
-  >>> chapter2.document
+  >>> chapter2.document.source
   <document u'Doc One'>
 
+Here we try to add another relation to chapter2 which must be possible.
+
+  >>> chapterRel3 = Document.chapters.new(chapter2)
+  >>> doc1.chapters = doc1.chapters + [chapterRel3]
+  >>> [c.target for c in doc1.chapters]
+  [<chapter u'Chapter One'>, <chapter u'Chapter Two'>, <chapter u'Chapter Two'>]
+
+  >>> chapter2.document.source
+  <document u'Doc One'>
+
   >>> doc1.chapters = None
   >>> doc1.chapters
   []

Modified: lovely.relation/trunk/src/lovely/relation/interfaces.py
===================================================================
--- lovely.relation/trunk/src/lovely/relation/interfaces.py	2007-10-18 19:53:21 UTC (rev 80931)
+++ lovely.relation/trunk/src/lovely/relation/interfaces.py	2007-10-19 09:58:34 UTC (rev 80932)
@@ -168,7 +168,7 @@
         """Target being pointed to in the relationship. Readonly.""")
 
 
-class IDataRelationPropertyOut(interface.Interface):
+class IDataRelationProperty(interface.Interface):
     """Extends the relation property to be able to annotate the relation"""
 
     def new(self, target):
@@ -179,7 +179,14 @@
         annotatable to allow data to be added to a relation.
         """
 
+class IDataRelationPropertyOut(IDataRelationProperty):
+    """Extends the relation property to be able to annotate the relation"""
 
+
+class IDataRelationPropertyIn(IDataRelationProperty):
+    """Extends the relation property to be able to annotate the relation"""
+
+
 class IRepair(interface.Interface):
     """Repair relations."""
 

Modified: lovely.relation/trunk/src/lovely/relation/property.py
===================================================================
--- lovely.relation/trunk/src/lovely/relation/property.py	2007-10-18 19:53:21 UTC (rev 80931)
+++ lovely.relation/trunk/src/lovely/relation/property.py	2007-10-19 09:58:34 UTC (rev 80932)
@@ -17,12 +17,18 @@
 """
 
 import interfaces
+
 from zope import interface
 from zope import component
+
 from zope.schema.fieldproperty import FieldProperty
 from zope.schema.interfaces import IList, ISequence
+
+from zope.app.intid.interfaces import IIntIds
+
 from app import O2OStringTypeRelationship
 
+
 _marker = object()
 
 def _ident(field):
@@ -64,6 +70,10 @@
         return component.getUtility(interfaces.IO2OStringTypeRelationships,
                                     name=self.utilName)
 
+    @property
+    def intids(self):
+        return component.getUtility(IIntIds)
+
     def getSourceTokens(self, target, relType):
         return self.util.findSourceTokens(target, relType)
 
@@ -104,8 +114,7 @@
                  'relations': relType,
                  'targets': tt})
             util.remove(rel.next())
-        for addT in list(
-                    util.relationIndex.resolveValueTokens(addTT, 'targets')):
+        for addT in list(self.resolveValueTokens(addTT, 'targets')):
             rel = self._instantiateRelation(source, [relType], addT)
             util.add(rel)
 
@@ -114,26 +123,26 @@
         if relations is not None:
             if not self.seqOut:
                 relations = [relations]
-            targets = [rel.target for rel in relations]
-            newTargetTokens = list(util.relationIndex.tokenizeValues(
-                                                        targets, 'targets'))
+            intids = self.intids
+            newRelationTokens = []
+            for rel in relations:
+                # we need this ugly hack to around NotYet exceptions
+                rel = intids.queryId(rel, rel)
+                newRelationTokens.append(intids.queryId(rel, rel))
         else:
             relations = []
-            newTargetTokens = []
-        sourceToken = util.relationIndex.tokenizeValues([source],
-                                                        'sources').next()
-        oldTargetTokens = util.findTargetTokens(source, relType)
-        newTT = set(newTargetTokens)
-        oldTT = set(oldTargetTokens)
+            newRelationTokens = []
+        oldRelationTokens = util.findSourceRelationshipTokens(source, relType)
+        newTT = set(newRelationTokens)
+        oldTT = set(oldRelationTokens)
         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())
-        for token, rel in zip(newTargetTokens, relations):
+        if delTT:
+            intids = self.intids
+            for relId in delTT:
+                rel = intids.getObject(relId)
+                util.remove(rel)
+        for token, rel in zip(newRelationTokens, relations):
             if token in addTT:
                 util.add(rel)
 
@@ -161,11 +170,38 @@
                  'sources': st})
             self.util.remove(rel.next())
 
-        for addT in list(
-            util.relationIndex.resolveValueTokens(addST, 'sources')):
+        for addT in list(self.resolveValueTokens(addST, 'sources')):
             rel = self._instantiateRelation(addST, [relType], target)
             self.util.add(rel)
 
+    def setSourceRelations(self, source, relations, relType):
+        util = self.util
+        if relations is not None:
+            if not self.seqOut:
+                relations = [relations]
+            intids = self.intids
+            newRelationTokens = []
+            for rel in relations:
+                # we need this ugly hack to around NotYet exceptions
+                rel = intids.queryId(rel, rel)
+                newRelationTokens.append(rel)
+        else:
+            relations = []
+            newRelationTokens = []
+        oldRelationTokens = util.findTargetRelationshipTokens(target, relType)
+        newTT = set(newRelationTokens)
+        oldTT = set(oldRelationTokens)
+        addTT = newTT.difference(oldTT)
+        delTT = oldTT.difference(newTT)
+        if delTT:
+            intids = self.intids
+            for relId in delTT:
+                rel = intids.getObject(relId)
+                util.remove(rel)
+        for token, rel in zip(newRelationTokens, relations):
+            if token in addTT:
+                util.add(rel)
+
     def tokenizeValues(self, values, index):
         return self.util.relationIndex.tokenizeValues(values, index)
 

Modified: lovely.relation/trunk/src/lovely/relation/property.txt
===================================================================
--- lovely.relation/trunk/src/lovely/relation/property.txt	2007-10-18 19:53:21 UTC (rev 80931)
+++ lovely.relation/trunk/src/lovely/relation/property.txt	2007-10-19 09:58:34 UTC (rev 80932)
@@ -240,12 +240,22 @@
   Traceback (most recent call last):
   ...
   ValueError: ('backrefs', 'field is readonly')
+
+Backref to doc 3 still exists.
+
   >>> n.backrefs[0] is doc3
   True
 
-Backref to doc 3 still exists.
+Setting mutliple relations to the same object can be done...
 
+  >>> doc3.related = [n, n]
 
+but only one relation is set
+
+  >>> doc3.related
+  [<note u'note'>]
+
+
 Use Of The Relationship Utility
 -------------------------------
 



More information about the Checkins mailing list