[Zope-CVS] SVN: zversioning/trunk/src/versioning/ Changed test setup.

Uwe Oestermeier uwe_oestermeier at iwm-kmrc.de
Wed Oct 13 11:09:47 EDT 2004


Log message for revision 28098:
  Changed test setup.

Changed:
  U   zversioning/trunk/src/versioning/MOTIVATION.txt
  U   zversioning/trunk/src/versioning/interfaces.py
  U   zversioning/trunk/src/versioning/policies.py
  U   zversioning/trunk/src/versioning/repository.py
  U   zversioning/trunk/src/versioning/storage.py
  D   zversioning/trunk/src/versioning/tests/repository_setup.py
  U   zversioning/trunk/src/versioning/tests/test_versioncontrol.py

-=-
Modified: zversioning/trunk/src/versioning/MOTIVATION.txt
===================================================================
--- zversioning/trunk/src/versioning/MOTIVATION.txt	2004-10-13 15:08:50 UTC (rev 28097)
+++ zversioning/trunk/src/versioning/MOTIVATION.txt	2004-10-13 15:09:45 UTC (rev 28098)
@@ -5,7 +5,7 @@
 
 We start by testing some of the existing infrastructure from zope.app.versioncontrol
 and try to apply the existing versioning to sample data. We take a simple
-folder tree with the following structure :
+folder tree with the following structure as our sample :
 
   sample
     |--> a <--|
@@ -18,12 +18,9 @@
   >>> from zope.app.versioncontrol.repository import declare_versioned
   >>> from versioning.tests.repository_setup import registerAdapter
   >>> from zope.app.folder import Folder, rootFolder
-  >>> from zope.app.tests.setup import setUpTraversal
   >>> from zope.app.traversing.interfaces import IPhysicallyLocatable
   >>> from ZODB.tests import util
   >>> from zope.app.versioncontrol.interfaces import IVersioned
-  >>> registerAdapter()
-  >>> setUpTraversal()
   >>> class TestFolder(Folder) :
   ...   zope.interface.implements(IPhysicallyLocatable)
   ...   def getPath(self) :
@@ -159,7 +156,7 @@
 how and what is versioned. The implementation here uses zope.app.copypastemove 
 to save each version as a normal copy of the original content object.
     
-    >>> from versioning.policies import VersionableAspectsAdapter
+    >>> import versioning.policies
     >>> def saveAsVersion(obj, histories) :       # a helper method XXX remove later
     ...     adapter = VersionableAspectsAdapter(obj, histories)
     ...     return adapter.writeAspects()
@@ -191,19 +188,19 @@
 of the policy. The simple implementation here replaces the original data
 with a copy of the versioned data. 
     
-    >>> def revertToVersion(obj, histories, selector) :
-    ...     adapter = VersionableAspectsAdapter(obj, histories)
+    >>> def revertToVersionCopy(obj, histories, selector) :
+    ...     adapter = versioning.policies.ReplaceWithCopyPolicy(obj, histories)
     ...     adapter.updateAspects(selector)
-    >>> revertToVersion(c, histories, '001')
+    >>> revertToVersionCopy(c, histories, '001')
 
 The fact that we used copies here requires 
-that we use new references that are established via traversal: 
+that we establish new references via traversal: 
 
     >>> new_c = b["c"]
     >>> new_c.text
     'First text version of c'
 
-When we get back a version the reference to an old and untouced items is still
+The reference to an old and untouched item is still
 intact :
     
     >>> new_c.refers_to == a
@@ -211,13 +208,46 @@
    
 The more interesting case arises if we update the refered object too :
    
-    >>> revertToVersion(a, histories, '001')
+    >>> revertToVersionCopy(a, histories, '001')
     >>> new_a = sample["a"]
     >>> new_c.refers_to == a
     True
     >>> new_c.refers_to == new_a
     False
 
-Depending on the use case this might be what you want. 
+Depending on the use case this might be what you want.
 
 
+A Second Implementation
+=======================
+
+A second policy uses the same copy routines to move objects into 
+the storage of object histories. Therefore we need not set up the 
+repository again. 
+
+What differs is the way how to revert
+the original object with versioned data. This implementation
+does not replace the original with a copy but updates only all fields
+with the versioned values.
+
+    >>> def revertToVersionState(obj, histories, selector) :
+    ...     adapter = versioning.policies.UpdateStatusPolicy(obj, histories)
+    ...     adapter.updateAspects(selector)
+    >>> a = new_a
+    >>> a.text
+    'First text version of a'
+    >>> revertToVersionState(new_a, histories, '002')
+    >>> a.text
+    'Second text version of a'
+    >>> a == new_a
+    True
+    
+
+
+
+
+
+
+
+
+

Modified: zversioning/trunk/src/versioning/interfaces.py
===================================================================
--- zversioning/trunk/src/versioning/interfaces.py	2004-10-13 15:08:50 UTC (rev 28097)
+++ zversioning/trunk/src/versioning/interfaces.py	2004-10-13 15:09:45 UTC (rev 28098)
@@ -232,11 +232,25 @@
       
     """
 
-class IVersionHistory(INameChooser) :
-    """ A version history of a single object should be able to
-        generate unique names for each version within the version history.
+class IVersionHistory(Interface) :
+    """ A version history of a single object. We choose an interface
+        that is provided by any zope folder or container, but can
+        also be easily adapted by any other sequence of objects.
     """
     
+    def keys() :
+        """ Returns a sequence of unique ids that can be used as access
+            keys. 
+        """
+    
+    def values() :
+        """ Returns a sequence of versioned objects.
+        """
+        
+    def __getitem__(key) :
+        """ Returns the version that is specified by the key. """
+  
+    
 
 # XXX 
 class IHistoryStorage(Interface) : # IHistories

Modified: zversioning/trunk/src/versioning/policies.py
===================================================================
--- zversioning/trunk/src/versioning/policies.py	2004-10-13 15:08:50 UTC (rev 28097)
+++ zversioning/trunk/src/versioning/policies.py	2004-10-13 15:09:45 UTC (rev 28098)
@@ -37,10 +37,7 @@
     def __init__(self, versionable, histories) :
         """ An adapter for transfering versionable aspects of an object to and from the
             version history of an object.
-            
-            context must be IVersionable
-            histories must be IHistories a storage of multiple object histories
-            
+          
             >>> from storage import SimpleHistoryStorage
             >>> from zope.app.tests.setup import buildSampleFolderTree
             >>> sample = buildSampleFolderTree()
@@ -65,26 +62,65 @@
         
     def writeAspects(self) :
         """ 
-            Save the versionable aspects of an original object into the object history.
+            Save the versionable aspects of an original object into 
+            the object history.
         """   
         history = self.histories.getHistory(self.versionable)
         return IObjectCopier(self.versionable).copyTo(history)        
       
-              
     def updateAspects(self, version_specifier) :
-        """ Read back the specified versioned aspects from the objects history. """
+        """ 
+            Read back the specified versioned aspects from the 
+            objects history.
+        """
+        
         history = self.histories.getHistory(self.versionable)
         version = history[version_specifier]
-        parent = self.versionable.__parent__
-        name = self.versionable.__name__       
+        self.copy(version, self.versionable)
+              
+    def copy(self, source, target) :
+        """ The internal copy routine """
+        parent = target.__parent__
+        name = target.__name__       
         del parent[name]
         IObjectCopier(version).copyTo(parent, name)
 
 
+class ReplaceWithCopyPolicy(VersionableAspectsAdapter) :
+    """ 
+        A specific policy that updates the original
+        by a replacement with a copy of versioned data.
+        As long as the user has only access via traversal
+        paths this policy requires that external python 
+        references are updated if needed.
+    """
   
+     def copy(self, source, target) :
+        """ Replaces the original with a copied version. """
+         
+        parent = target.__parent__
+        name = target.__name__       
+        del parent[name]
+        IObjectCopier(version).copyTo(parent, name)
+ 
+ 
+class UpdateStatusPolicy(VersionableAspectsAdapter) :
+    """ Implements a more complex policy that leaves Python
+        references of the original content objects intact.
+        
+        It also assumes that we only version objects
+        that have been persistently stored (and thus have a _p_oid)
+        
+    """
+    
+    def copy(self, source, target) :
+        """ Copies the state of source to target. """
+        for key, value in source.__getstate__.items() :
+            if key not in ('__name__', '__parent__') :
+                setattr(target, key, value)
 
+       
 
-
 def test_suite():
     return unittest.TestSuite((
         doctest.DocTestSuite(),

Modified: zversioning/trunk/src/versioning/repository.py
===================================================================
--- zversioning/trunk/src/versioning/repository.py	2004-10-13 15:08:50 UTC (rev 28097)
+++ zversioning/trunk/src/versioning/repository.py	2004-10-13 15:09:45 UTC (rev 28098)
@@ -27,27 +27,6 @@
 from zope.testing import doctest
 from zope.app.tests import ztapi
 
-"""Just here for historical reasons, may be removed later
-class DummyHistoryStorage:
-    
-    def __init__(self):
-        self._histories = {}
-    
-    def getTicket(self, obj):
-        return id(obj)
-    
-    def _getHistory(self, obj):
-        return self._histories.setdefault(id(obj), [])
-    
-    def save(self, obj):
-        import copy
-        obj_copy = copy.copy(obj)
-        self._getHistory(obj).append(obj_copy)
-        return self.getTicket(obj_copy)
-        
-    def load(self, obj, selector):
-        return self._histories[id(obj)][selector]
-"""
 
 class DummyCheckoutAware(object):
     """Just ignores checkin and checkout without generating exceptions.
@@ -138,15 +117,11 @@
             (obj, self.histories), IVersionableAspects)
         versionable_state.updateAspects(specifier)
         
-    def getVersionHistory(self, obj, selector):
-        versionable_state = zapi.getMultiAdapter(
-            (obj, self.histories), IVersionableAspects)
-        return versionable_state.getApsectsHistory(specifier)
+    def getVersionHistory(self, obj):
+        return self.histories.getVersionHistory(obj)
         
     def getMetadataHistory(self, obj):
-        versionable_state = zapi.getMultiAdapter(
-            (obj, self.histories), IVersionableAspects)
-        return versionable_state.getMetadataHistory(specifier)
+        return self.histories.getMetadataHistory(obj)
         
 
 class CheckoutCheckinRepository(CopyModifyMergeRepository):

Modified: zversioning/trunk/src/versioning/storage.py
===================================================================
--- zversioning/trunk/src/versioning/storage.py	2004-10-13 15:08:50 UTC (rev 28097)
+++ zversioning/trunk/src/versioning/storage.py	2004-10-13 15:09:45 UTC (rev 28098)
@@ -84,11 +84,22 @@
         self[ticket] = history
         return ticket
         
-    def getHistory(self, obj):
-        """Internal: return a version history given a version history id."""
+    def getVersionHistory(self, obj):
+        """ Returns a version history given a version history id."""
         ticket = self.getTicket(obj)
         return self[ticket]
         
+    def listVersions(self, obj) :
+        """ Returns the versions of an object. The versions are
+            returned sorted in the order of appearance. """
+        list = self.history.values()
+        list.sort()
+        return list
+        
+    def getMetadataHistory(self, obj) :
+        """ Returns a version history given a version history id."""
+        NotImplementedError("metadata support not implemented")
+        
     def getVersion(self, obj, selector) :
         """ Returns the version of an object that is specified by selector. """
         history = self.getHistory(obj)

Deleted: zversioning/trunk/src/versioning/tests/repository_setup.py
===================================================================
--- zversioning/trunk/src/versioning/tests/repository_setup.py	2004-10-13 15:08:50 UTC (rev 28097)
+++ zversioning/trunk/src/versioning/tests/repository_setup.py	2004-10-13 15:09:45 UTC (rev 28098)
@@ -1,113 +0,0 @@
-"""Some setup stuff not being intresting for doc tests
-"""
-
-import persistent
-import zope.interface
-import zope.app.annotation.attribute
-import zope.app.annotation.interfaces
-import zope.app.traversing.interfaces
-from zope.app.versioncontrol import interfaces
-from zope.app.tests import ztapi
-
-from zope.interface import classImplements
-
-from zope.app.traversing.interfaces import ITraversable, ITraverser
-from zope.app.traversing.interfaces import IPhysicallyLocatable
-from zope.app.traversing.interfaces import IContainmentRoot
-from zope.app.traversing.adapters import DefaultTraversable
-from zope.app.location.traversing import LocationPhysicallyLocatable
-from zope.app.traversing.adapters import RootPhysicallyLocatable
-from zope.app.traversing.adapters import Traverser
-
-from zope.app.annotation.interfaces import IAttributeAnnotatable
-from zope.app.annotation.attribute import AttributeAnnotations
-from zope.app.dublincore.interfaces import IZopeDublinCore
-from zope.app.dublincore.annotatableadapter import ZDCAnnotatableAdapter
-from zope.app.annotation.interfaces import IAnnotatable, IAnnotations
-from zope.app.container.interfaces import IContainer
-from zope.app.file.interfaces import IFile
-from zope.app.file.file import File
-from zope.app.folder.folder import Folder
-
-from zope.app.copypastemove.interfaces import IObjectCopier
-from zope.app.copypastemove import ObjectCopier
-
-
-from zope.app.container.interfaces import IWriteContainer, INameChooser
-from zope.app.container.contained import NameChooser
-
-
-def registerAdapter() :
-    """ Register some common adapter. """ 
-
-    classImplements(File, IAttributeAnnotatable)
-    classImplements(Folder, IAttributeAnnotatable)
-
-    ztapi.provideAdapter(IAttributeAnnotatable, IAnnotations, AttributeAnnotations)
-    ztapi.provideAdapter(None, ITraverser, Traverser)
-    ztapi.provideAdapter(None, ITraversable, DefaultTraversable)
-    ztapi.provideAdapter(None, IPhysicallyLocatable, LocationPhysicallyLocatable)
-    ztapi.provideAdapter(IContainmentRoot, IPhysicallyLocatable, RootPhysicallyLocatable)
-    ztapi.provideAdapter(IAnnotatable, IZopeDublinCore, ZDCAnnotatableAdapter)
-
-    # for copy and moves
-    ztapi.provideAdapter(None, IObjectCopier, ObjectCopier)
-    ztapi.provideAdapter(IWriteContainer, INameChooser, NameChooser)
-    
-    
-def buildDatabaseRoot():
-    """Opens a connection to a test database and returns the root object
-    """
-     
-    # Now we need to create a database with an instance of our sample object 
-    # to work with:
-    
-    from ZODB.tests import util
-    db = util.DB()
-    connection = db.open()
-    return connection.root()
-
-def buildRepository(factory=zope.app.versioncontrol.repository.Repository, interaction=True):
-    """Setup a zope.app.versioncontrol repository
-    
-    Placing an object under version control requires an instance of an
-    `IVersionControl` object.  This package provides an implementation of 
-    this interface on the `Repository` class (from
-    `zope.app.versioncontrol.repository`).  Only the `IVersionControl` 
-    instance is responsible for providing version control operations; 
-    an instance should never be asked to perform operations directly.
-    """
-    import zope.app.versioncontrol.repository
-    import zope.interface.verify
-    
-    repository = factory()
-    assert zope.interface.verify.verifyObject(
-               interfaces.IVersionControl,
-               repository)
-               
-    if interaction :
-
-        # In order to actually use version control, there must be an
-        # interaction.  This is needed to allow the framework to determine the
-        # user making changes.  Let's set up an interaction now. First we need a
-        # principal. For our purposes, a principal just needs to have an id:
-        class FauxPrincipal:
-           def __init__(self, id):
-               self.id = id
-        principal = FauxPrincipal('bob')
-    
-        # Then we need to define an participation for the principal in the
-        # interaction:
-        class FauxParticipation:
-            interaction=None
-            def __init__(self, principal):
-                self.principal = principal
-        participation = FauxParticipation(principal)
-    
-        # Finally, we can create the interaction:
-        import zope.security.management
-        zope.security.management.newInteraction(participation)
-
-    return repository
-
-

Modified: zversioning/trunk/src/versioning/tests/test_versioncontrol.py
===================================================================
--- zversioning/trunk/src/versioning/tests/test_versioncontrol.py	2004-10-13 15:08:50 UTC (rev 28097)
+++ zversioning/trunk/src/versioning/tests/test_versioncontrol.py	2004-10-13 15:09:45 UTC (rev 28098)
@@ -20,7 +20,7 @@
 import unittest
 from zope.interface import implements
 from zope.app.container.sample import SampleContainer
-from zope.app.tests.placelesssetup import setUp, tearDown
+from zope.app.tests import placelesssetup
 from zope.app.tests import ztapi
 
 # import basic test infrastructure from existing version control implementation
@@ -28,21 +28,130 @@
 
 from zope.testing import doctest
 
-from zope.app.tests.setup import buildSampleFolderTree
 
-def setUpOldStyleVersionControl() :
-    """ Returns s small test site of original content objects:
+import persistent
+import zope.interface
+import zope.app.annotation.attribute
+import zope.app.annotation.interfaces
+import zope.app.traversing.interfaces
+import zope.app.versioncontrol.repository
+import zope.interface.verify
+
+from zope.app.versioncontrol import interfaces
+from zope.app.tests import ztapi
+from zope.app.tests.setup import setUpTraversal
+from zope.interface import classImplements
+
+from zope.app.traversing.interfaces import ITraversable, ITraverser
+from zope.app.traversing.interfaces import IPhysicallyLocatable
+from zope.app.traversing.interfaces import IContainmentRoot
+from zope.app.traversing.adapters import DefaultTraversable
+from zope.app.location.traversing import LocationPhysicallyLocatable
+from zope.app.traversing.adapters import RootPhysicallyLocatable
+from zope.app.traversing.adapters import Traverser
+
+from zope.app.annotation.interfaces import IAttributeAnnotatable
+from zope.app.annotation.attribute import AttributeAnnotations
+from zope.app.dublincore.interfaces import IZopeDublinCore
+from zope.app.dublincore.annotatableadapter import ZDCAnnotatableAdapter
+from zope.app.annotation.interfaces import IAnnotatable, IAnnotations
+from zope.app.container.interfaces import IContainer
+from zope.app.file.interfaces import IFile
+from zope.app.file.file import File
+from zope.app.folder.folder import Folder
+
+from zope.app.copypastemove.interfaces import IObjectCopier
+from zope.app.copypastemove import ObjectCopier
+
+from zope.app.container.interfaces import IWriteContainer, INameChooser
+from zope.app.container.contained import NameChooser
+
+
+def setUp(test) :
+    """ Sets up a test and registers some commonly used adapters. """
     
-        >>> folders = buildSampleFolderTree()
-        >>> folders is not None
-        True
-      
+    placelesssetup.setUp()
+    setUpTraversal()
+ 
+    classImplements(File, IAttributeAnnotatable)
+    classImplements(Folder, IAttributeAnnotatable)
+
+    ztapi.provideAdapter(IAttributeAnnotatable, IAnnotations, AttributeAnnotations)
+    ztapi.provideAdapter(None, ITraverser, Traverser)
+    ztapi.provideAdapter(None, ITraversable, DefaultTraversable)
+    ztapi.provideAdapter(None, IPhysicallyLocatable, LocationPhysicallyLocatable)
+    ztapi.provideAdapter(IContainmentRoot, IPhysicallyLocatable, RootPhysicallyLocatable)
+    ztapi.provideAdapter(IAnnotatable, IZopeDublinCore, ZDCAnnotatableAdapter)
+
+    # for copy and moves
+    ztapi.provideAdapter(None, IObjectCopier, ObjectCopier)
+    ztapi.provideAdapter(IWriteContainer, INameChooser, NameChooser)
+
+ 
+def tearDown(test) :
+    placelesssetup.tearDown()
+
+   
+    
+def buildDatabaseRoot():
+    """Opens a connection to a test database and returns the root object
     """
+     
+    # Now we need to create a database with an instance of our sample object 
+    # to work with:
+    
+    from ZODB.tests import util
+    db = util.DB()
+    connection = db.open()
+    return connection.root()
 
+def buildRepository(factory=zope.app.versioncontrol.repository.Repository, interaction=True):
+    """Setup a zope.app.versioncontrol repository
+    
+    Placing an object under version control requires an instance of an
+    `IVersionControl` object.  This package provides an implementation of 
+    this interface on the `Repository` class (from
+    `zope.app.versioncontrol.repository`).  Only the `IVersionControl` 
+    instance is responsible for providing version control operations; 
+    an instance should never be asked to perform operations directly.
+    """
+    
+    repository = factory()
+    assert zope.interface.verify.verifyObject(
+               interfaces.IVersionControl,
+               repository)
+               
+    if interaction :
+
+        # In order to actually use version control, there must be an
+        # interaction.  This is needed to allow the framework to determine the
+        # user making changes.  Let's set up an interaction now. First we need a
+        # principal. For our purposes, a principal just needs to have an id:
+        class FauxPrincipal:
+           def __init__(self, id):
+               self.id = id
+        principal = FauxPrincipal('bob')
+    
+        # Then we need to define an participation for the principal in the
+        # interaction:
+        class FauxParticipation:
+            interaction=None
+            def __init__(self, principal):
+                self.principal = principal
+        participation = FauxParticipation(principal)
+    
+        # Finally, we can create the interaction:
+        import zope.security.management
+        zope.security.management.newInteraction(participation)
+
+    return repository
+
+
 def test_suite():
     return unittest.TestSuite((
         doctest.DocTestSuite(),
         doctest.DocFileSuite("../README.txt", setUp=setUp, tearDown=tearDown),
+        doctest.DocFileSuite("../MOTIVATION.txt", setUp=setUp, tearDown=tearDown),
         ))
 if __name__=='__main__':
     unittest.main(defaultTest='test_suite')



More information about the Zope-CVS mailing list