[Zope-CVS] SVN: zversioning/trunk/src/versioning/ Adapted tests

Uwe Oestermeier uwe_oestermeier at iwm-kmrc.de
Wed Oct 13 07:36:39 EDT 2004


Log message for revision 28060:
  Adapted tests

Changed:
  A   zversioning/trunk/src/versioning/MOTIVATION.txt
  D   zversioning/trunk/src/versioning/README.txt
  U   zversioning/trunk/src/versioning/policies.py
  U   zversioning/trunk/src/versioning/storage.py

-=-
Copied: zversioning/trunk/src/versioning/MOTIVATION.txt (from rev 28045, zversioning/trunk/src/versioning/README.txt)
===================================================================
--- zversioning/trunk/src/versioning/README.txt	2004-10-13 08:27:38 UTC (rev 28045)
+++ zversioning/trunk/src/versioning/MOTIVATION.txt	2004-10-13 11:36:38 UTC (rev 28060)
@@ -0,0 +1,223 @@
+======================================
+Motivation for a new Versioning Scheme
+======================================
+
+
+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 :
+
+  sample
+    |--> a <--|
+    |--> b    |
+         |--> c
+     
+
+  >>> import zope.app.versioncontrol.interfaces
+  >>> from zope.interface import directlyProvides
+  >>> 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) :
+  ...       return ""
+  
+  >>> sample = TestFolder()
+  >>> directlyProvides(sample, zope.app.traversing.interfaces.IContainmentRoot)
+  >>> a = sample["a"] = TestFolder()
+  >>> b = sample["b"] = TestFolder()
+  >>> c = b["c"] = TestFolder()
+  >>> for x in (sample, a, b, c) :
+  ...     directlyProvides(x, zope.app.versioncontrol.interfaces.IVersionable)
+  >>> [x for x in sample.keys()]
+  [u'a', u'b']
+  
+  
+The interesting test case is the reference that uses references outside
+the hierarchical ones, which should be naturally handled in Zope3:
+
+  >>> c.refers_to = a
+  >>> a == c.refers_to
+  True
+
+In order to show some limitations of the current implementation we use a
+prebuild version control repository :
+
+  >>> from versioning.tests.repository_setup import buildRepository, buildDatabaseRoot
+  >>> db_root = buildDatabaseRoot()
+  >>> db_root["sample"] = sample 
+  >>> repository = buildRepository()
+  
+The current policy forces us to remove __parent__ and __name__. We'll do that
+by specializing the standard adapter that removes nothing:
+
+  >>> from zope.app.versioncontrol.nonversioned import StandardNonVersionedDataAdapter
+  >>> class NonVersionedAdapter(StandardNonVersionedDataAdapter) :
+  ...     attrs = ("__name__", "__parent__")   # remove __name__ and __parent from versioning
+  
+  
+  >>> from zope.app.tests import ztapi
+  >>> ztapi.provideAdapter(zope.app.versioncontrol.interfaces.IVersionable,
+  ...                       zope.app.versioncontrol.interfaces.INonVersionedData,
+  ...                       NonVersionedAdapter)
+  >>> zope.app.versioncontrol.interfaces.INonVersionedData(a) is not None
+  True
+
+Now we can put our example data under version control:
+
+  >>> repository.applyVersionControl(sample)
+  >>> repository.applyVersionControl(a)
+  >>> repository.applyVersionControl(b)
+  >>> repository.applyVersionControl(c)
+  >>> util.commit()
+  >>> [IVersioned.providedBy(x) for x in (sample, a, b, c)]
+  [True, True, True, True]
+  >>> [x for x in sample.keys()]
+  [u'a', u'b']
+  
+
+The implementation in zope.app.versioncontrol breaks any database identity references
+because a pickle version is used that ignores all references that point
+outside the sub tree. In the example above this means, that the version of c loses
+its reference to a because c is not contained in a. (See 
+ zope.app.versioncontrol.version.cloneByPickle)
+
+  >>> def accessVersion(repository, obj) :
+  ...   info = repository.getVersionInfo(obj)
+  ...   return repository.getVersionOfResource(info.history_id, 'mainline')
+  >>> new_a = accessVersion(repository, a)
+  >>> new_b = accessVersion(repository, b)
+  >>> new_c = accessVersion(repository, c)
+  >>> [x for x in sample.keys()]
+  [u'a', u'b']
+
+Now the reference from b to c is invalid ...
+  
+  >>> new_b["c"] == new_c
+  False
+  
+as well as the reference from c to a :
+  
+  >>> new_c.refers_to == new_a
+  False
+
+  
+This demonstrates that the reference to a is not preserved, which is the major
+motivation for a new implementation.
+
+
+
+A First Implementation
+======================
+
+We want to use versioning with objects other than standard zope objects that use
+only the standard containment structure meachanism. In the same time some parts
+of the versioning system should be pluggable, e.g. the storage for the object histories,
+the locking mechanism etc.
+
+Let's set up some initial content :
+
+    >>> a.text = "First text version of a"
+    >>> c.text = "First text version of c"
+
+To achieve this goal we refactored the components of the versioning system.
+Let's start with the basic building block, a storage that holds version histories
+of several objects. Note that this implementation does not collide with the
+implementation in zope.app.versioncontrol. This versioning scheme does not attach any
+information to the versioned objects and keeps the necessary bookeeping information 
+encapsulated in the storage of object histories.
+
+
+    >>> from versioning.storage import SimpleHistoryStorage
+    >>> histories = SimpleHistoryStorage()
+    
+The versioning system that puts object under versioning control must register
+the object in the histories storage (this will be called later on by
+IVersionControl.applyVersionControl) :
+
+    >>> histories.register(sample)
+    '\x00\x00\x00\x00\x00\x00\x00\x01'
+    >>> histories.register(a)
+    '\x00\x00\x00\x00\x00\x00\x00\x04'
+    >>> histories.register(b)
+    '\x00\x00\x00\x00\x00\x00\x00\x05'
+    >>> histories.register(c)
+    '\x00\x00\x00\x00\x00\x00\x00\t'
+    >>> util.commit()
+    >>> len(histories.values())
+    4
+    
+The SimpleHistoryStorage.register method copies nothing. The copy process is 
+managed by a multi adapter that implements a versioning policy, i.e. determines
+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
+    >>> def saveAsVersion(obj, histories) :       # a helper method XXX remove later
+    ...     adapter = VersionableAspectsAdapter(obj, histories)
+    ...     return adapter.writeAspects()
+    >>> saveAsVersion(sample, histories)
+    '001'
+    >>> saveAsVersion(a, histories)
+    '001'
+    >>> saveAsVersion(b, histories)
+    '001'
+    >>> saveAsVersion(c, histories)
+    '001'
+    >>> version = histories[a._p_oid]['001']
+    >>> version.text
+    'First text version of a'
+    
+Add some additional content versions :
+
+    >>> a.text = "Second text version of a"
+    >>> c.text = "Second text version of c"
+    >>> saveAsVersion(a, histories)
+    '002'
+    >>> version = histories[a._p_oid]['002']
+    >>> version.text
+    'Second text version of a'
+    >>> saveAsVersion(c, histories)
+    '002'
+
+Now let's update the original object with versioned data. This again is a matter
+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)
+    ...     adapter.updateAspects(selector)
+    >>> revertToVersion(c, histories, '001')
+
+The fact that we used copies here requires 
+that we use new references that are established 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
+intact :
+    
+    >>> new_c.refers_to == a
+    True
+   
+The more interesting case arises if we update the refered object too :
+   
+    >>> revertToVersion(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. 
+
+

Deleted: zversioning/trunk/src/versioning/README.txt
===================================================================
--- zversioning/trunk/src/versioning/README.txt	2004-10-13 11:05:24 UTC (rev 28059)
+++ zversioning/trunk/src/versioning/README.txt	2004-10-13 11:36:38 UTC (rev 28060)
@@ -1,152 +0,0 @@
-Versioning
-==========
-
-
-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 :
-
-  sample
-    |--> a <--|
-    |--> b    |
-         |--> c
-     
-
-  >>> import zope.app.versioncontrol.interfaces
-  >>> from zope.interface import directlyProvides
-  >>> 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) :
-  ...       return ""
-  
-  >>> sample = TestFolder()
-  >>> directlyProvides(sample, zope.app.traversing.interfaces.IContainmentRoot)
-  >>> a = sample["a"] = TestFolder()
-  >>> b = sample["b"] = TestFolder()
-  >>> c = b["c"] = TestFolder()
-  >>> for x in (sample, a, b, c) :
-  ...     directlyProvides(x, zope.app.versioncontrol.interfaces.IVersionable)
-  
-The interesting test case is the reference that uses references outside
-the hierarchical ones, which should be naturally handled in Zope3:
-
-  >>> c.refers_to = a
-  >>> a == c.refers_to
-  True
-
-In order to show some limitations of the current implementation we use a
-prebuild version control repository :
-
-  >>> from versioning.tests.repository_setup import buildRepository, buildDatabaseRoot
-  >>> db_root = buildDatabaseRoot()
-  >>> db_root["sample"] = sample 
-  >>> repository = buildRepository()
-  
-The current policy forces us to remove __parent__ and __name__. We'll do that
-by specializing the standard adapter that removes nothing:
-
-  >>> from zope.app.versioncontrol.nonversioned import StandardNonVersionedDataAdapter
-  >>> class NonVersionedAdapter(StandardNonVersionedDataAdapter) :
-  ...     attrs = ("__name__", "__parent__")   # remove __name__ and __parent from versioning
-  
-  
-  >>> from zope.app.tests import ztapi
-  >>> ztapi.provideAdapter(zope.app.versioncontrol.interfaces.IVersionable,
-  ...                       zope.app.versioncontrol.interfaces.INonVersionedData,
-  ...                       NonVersionedAdapter)
-  >>> zope.app.versioncontrol.interfaces.INonVersionedData(a) is not None
-  True
-
-Now we can put our example data under version control:
-
-  >>> repository.applyVersionControl(sample)
-  >>> repository.applyVersionControl(a)
-  >>> repository.applyVersionControl(b)
-  >>> repository.applyVersionControl(c)
-  >>> util.commit()
-  >>> [IVersioned.providedBy(x) for x in (sample, a, b, c)]
-  [True, True, True, True]
-    
-
-The implementation in zope.app.versioncontrol breaks any database identity references
-because a pickle version is used that ignores all references that point
-outside the sub tree. In the example above this means, that the version of c loses
-its reference to a because c is not contained in a. (See 
- zope.app.versioncontrol.version.cloneByPickle)
-
-  >>> def accessVersion(repository, obj) :
-  ...   info = repository.getVersionInfo(obj)
-  ...   return repository.getVersionOfResource(info.history_id, 'mainline')
-  >>> new_a = accessVersion(repository, a)
-  >>> new_b = accessVersion(repository, b)
-  >>> new_c = accessVersion(repository, c)
-
-Now the reference from b to c is invalid ...
-  
-  >>> new_b["c"] == new_c
-  False
-  
-as well as the reference from c to a :
-  
-  >>> new_c.refers_to == new_a
-  False
-
-  
-This demonstrates that the reference to a is not preserved, which is the major
-motivation for a new implementation.
-
-
-
-
-Alternative implementation
---------------------------
-
-We want to use versioning with objects other than standard zope objects that use
-only the standard containment structure meachanism. In the same time some parts
-of the versioning system should be pluggable, e.g. the storage for the object histories,
-the locking mechanism etc.
-
-We start with the basic building blocks, a storage that holds version histories
-of several objects. Note that this implementation does not collide with the
-implementation in zope.app.versioncontrol. This versioning scheme does not attach any
-information to the versioned objects and keeps the necessary bookeeping information 
-encapsulated in the storage of object histories.
-
-    >>> from versioning.storage import SimpleHistoryStorage
-    >>> from versioning.policies import VersionableAspectsAdapter
-    >>> histories = SimpleHistoryStorage()
-    >>> histories.register(a)
-    '\x00\x00\x00\x00\x00\x00\x00\x04'
-    >>> histories.register(b)
-    '\x00\x00\x00\x00\x00\x00\x00\x05'
-    >>> util.commit()
-    >>> len(histories.values())
-    2
-    >>> [x for x in histories.keys()]
-    [u'\x00\x00\x00\x00\x00\x00\x00\x04', u'\x00\x00\x00\x00\x00\x00\x00\x05']
-    >>> adapter = VersionableAspectsAdapter(a, histories)
-    >>> adapter.writeAspects()
-    '001'
-    
-    
-    
-    
-
-
-
-    
-
-
-
-
-
-

Modified: zversioning/trunk/src/versioning/policies.py
===================================================================
--- zversioning/trunk/src/versioning/policies.py	2004-10-13 11:05:24 UTC (rev 28059)
+++ zversioning/trunk/src/versioning/policies.py	2004-10-13 11:36:38 UTC (rev 28060)
@@ -76,8 +76,9 @@
         history = self.histories.getHistory(self.versionable)
         version = history[version_specifier]
         parent = self.versionable.__parent__
-        del parent[self.versionable.__name__]
-        IObjectCopier(self.versionable).copyTo(parent)
+        name = self.versionable.__name__       
+        del parent[name]
+        IObjectCopier(version).copyTo(parent, name)
 
 
   

Modified: zversioning/trunk/src/versioning/storage.py
===================================================================
--- zversioning/trunk/src/versioning/storage.py	2004-10-13 11:05:24 UTC (rev 28059)
+++ zversioning/trunk/src/versioning/storage.py	2004-10-13 11:36:38 UTC (rev 28060)
@@ -89,6 +89,11 @@
         ticket = self.getTicket(obj)
         return self[ticket]
         
+    def getVersion(self, obj, selector) :
+        """ Returns the version of an object that is specified by selector. """
+        history = self.getHistory(obj)
+        return history[selector]
+        
   
              
    



More information about the Zope-CVS mailing list