[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