[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/ Refactored the way objects are renamed:

Garrett Smith garrett at mojave-corp.com
Thu Feb 10 16:48:46 EST 2005


Log message for revision 29109:
  Refactored the way objects are renamed:
  
  - Added IContainerItemRenamer
  - Added a renamer for standard containers and ordered containers
  - Deprecated copypastemove.rename

Changed:
  U   Zope3/trunk/src/zope/app/container/browser/contents.py
  U   Zope3/trunk/src/zope/app/container/browser/tests/test_contents.py
  U   Zope3/trunk/src/zope/app/copypastemove/__init__.py
  U   Zope3/trunk/src/zope/app/copypastemove/configure.zcml
  U   Zope3/trunk/src/zope/app/copypastemove/interfaces.py
  U   Zope3/trunk/src/zope/app/copypastemove/tests/test_rename.py
  U   Zope3/trunk/src/zope/app/ftp/__init__.py
  U   Zope3/trunk/src/zope/app/ftp/tests/test_ftpview.py

-=-
Modified: Zope3/trunk/src/zope/app/container/browser/contents.py
===================================================================
--- Zope3/trunk/src/zope/app/container/browser/contents.py	2005-02-10 21:11:09 UTC (rev 29108)
+++ Zope3/trunk/src/zope/app/container/browser/contents.py	2005-02-10 21:48:46 UTC (rev 29109)
@@ -16,7 +16,7 @@
 $Id$
 """
 __docformat__ = 'restructuredtext'
-        
+
 import urllib
 
 from zope.app.traversing.interfaces import TraversalError
@@ -33,7 +33,7 @@
 from zope.app.copypastemove.interfaces import IPrincipalClipboard
 from zope.app.copypastemove.interfaces import IObjectCopier
 from zope.app.copypastemove.interfaces import IObjectMover
-from zope.app.copypastemove import rename
+from zope.app.copypastemove.interfaces import IContainerItemRenamer
 from zope.app.principalannotation.interfaces import IPrincipalAnnotationUtility
 
 from zope.app.container.browser.adding import Adding
@@ -205,9 +205,10 @@
         ids = request.get("rename_ids")
         newids = request.get("new_value")
 
+        renamer = IContainerItemRenamer(self.context)
         for oldid, newid in map(None, ids, newids):
             if newid != oldid:
-                rename(self.context, oldid, newid)
+                renamer.renameItem(oldid, newid)
 
     def changeTitle(self):
         """Given a sequence of tuples of old, new ids we rename"""
@@ -241,7 +242,7 @@
             # above, because there is no "+" view.
             adding.__parent__ = self.context
             adding.__name__ = '+'
-             
+
         adding.action(request['type_name'], new)
 
     def removeObjects(self):

Modified: Zope3/trunk/src/zope/app/container/browser/tests/test_contents.py
===================================================================
--- Zope3/trunk/src/zope/app/container/browser/tests/test_contents.py	2005-02-10 21:11:09 UTC (rev 29108)
+++ Zope3/trunk/src/zope/app/container/browser/tests/test_contents.py	2005-02-10 21:48:46 UTC (rev 29109)
@@ -23,8 +23,10 @@
 
 from zope.app.traversing.api import traverse
 from zope.app.copypastemove.interfaces import IObjectMover, IObjectCopier
+from zope.app.copypastemove.interfaces import IContainerItemRenamer
 
 from zope.app.copypastemove import ObjectMover, ObjectCopier
+from zope.app.copypastemove import ContainerItemRenamer
 
 from zope.app.container.interfaces import IObjectRemovedEvent
 from zope.interface import Interface, implements
@@ -36,6 +38,7 @@
 from zope.app.principalannotation.interfaces import IPrincipalAnnotationUtility
 from zope.app.annotation.interfaces import IAnnotations
 from zope.app.container.contained import contained
+from zope.app.container.interfaces import IContainer, IContained
 
 class BaseTestContentsBrowserView(PlacefulSetup):
     """Base class for testing browser contents.
@@ -50,10 +53,12 @@
     def setUp(self):
         PlacefulSetup.setUp(self)
         PlacefulSetup.buildFolders(self)
-        
-        ztapi.provideAdapter(None, IObjectCopier, ObjectCopier)
-        ztapi.provideAdapter(None, IObjectMover, ObjectMover)
 
+        ztapi.provideAdapter(IContained, IObjectCopier, ObjectCopier)
+        ztapi.provideAdapter(IContained, IObjectMover, ObjectMover)
+        ztapi.provideAdapter(IContainer, IContainerItemRenamer,
+            ContainerItemRenamer)
+
         ztapi.provideAdapter(IAnnotations, IPrincipalClipboard,
                              PrincipalClipboard)
         ztapi.provideUtility(IPrincipalAnnotationUtility,
@@ -88,7 +93,7 @@
         container = self._TestView__newContext()
         subcontainer = self._TestView__newContext()
         container[u'f\xf6\xf6'] = subcontainer
-        
+
         fc = self._TestView__newView(container)
         info_list = fc.listContentInfo()
 
@@ -160,7 +165,7 @@
 
 
 class Principal(object):
-    
+
     id = 'bob'
 
 
@@ -169,8 +174,10 @@
     def setUp(self):
         PlacefulSetup.setUp(self)
         PlacefulSetup.buildFolders(self)
-        ztapi.provideAdapter(None, IObjectCopier, ObjectCopier)
-        ztapi.provideAdapter(None, IObjectMover, ObjectMover)
+        ztapi.provideAdapter(IContained, IObjectCopier, ObjectCopier)
+        ztapi.provideAdapter(IContained, IObjectMover, ObjectMover)
+        ztapi.provideAdapter(IContainer, IContainerItemRenamer,
+            ContainerItemRenamer)
 
         ztapi.provideAdapter(IAnnotations, IPrincipalClipboard,
                              PrincipalClipboard)

Modified: Zope3/trunk/src/zope/app/copypastemove/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/copypastemove/__init__.py	2005-02-10 21:11:09 UTC (rev 29108)
+++ Zope3/trunk/src/zope/app/copypastemove/__init__.py	2005-02-10 21:48:46 UTC (rev 29109)
@@ -19,17 +19,26 @@
 
 from zope.interface import implements, Invalid
 from zope.exceptions import NotFoundError, DuplicationError
+from zope.component import adapts
+from zope.event import notify
 
 from zope.app import zapi
+from zope.app.annotation.interfaces import IAnnotations
 from zope.app.container.sample import SampleContainer
-from zope.event import notify
 from zope.app.event.objectevent import ObjectCopiedEvent
-from zope.app.copypastemove.interfaces import IObjectMover
-from zope.app.copypastemove.interfaces import IObjectCopier
 from zope.app.location.pickling import locationCopy
+from zope.app.container.interfaces import IContainer, IOrderedContainer
+from zope.app.container.interfaces import IContained
 from zope.app.container.interfaces import INameChooser
 from zope.app.container.constraints import checkObject
 
+from zope.app.copypastemove.interfaces import IObjectMover
+from zope.app.copypastemove.interfaces import IObjectCopier
+from zope.app.copypastemove.interfaces import IContainerItemRenamer
+from zope.app.copypastemove.interfaces import IPrincipalClipboard
+
+import warnings # BBB (remove in 3.3)
+
 class ObjectMover(object):
     """Adapter for moving objects between containers
 
@@ -160,6 +169,8 @@
 
     """
 
+    adapts(IContained)
+
     implements(IObjectMover)
 
     def __init__(self, object):
@@ -167,10 +178,10 @@
         self.__parent__ = object # TODO: see if we can automate this
 
     def moveTo(self, target, new_name=None):
-        '''Move this object to the `target` given.
+        """Move this object to the `target` given.
 
         Returns the new name within the `target`
-        Typically, the `target` is adapted to `IPasteTarget`.'''
+        Typically, the `target` is adapted to `IPasteTarget`."""
 
         obj = self.context
         container = obj.__parent__
@@ -193,15 +204,15 @@
         return new_name
 
     def moveable(self):
-        '''Returns ``True`` if the object is moveable, otherwise ``False``.'''
+        """Returns ``True`` if the object is moveable, otherwise ``False``."""
         return True
 
     def moveableTo(self, target, name=None):
-        '''Say whether the object can be moved to the given target.
+        """Say whether the object can be moved to the given target.
 
         Returns ``True`` if it can be moved there. Otherwise, returns
         ``False``.
-        '''
+        """
         if name is None:
             name = self.context.__name__
         try:
@@ -350,6 +361,8 @@
 
     """
 
+    adapts(IContained)
+
     implements(IObjectCopier)
 
     def __init__(self, object):
@@ -360,7 +373,7 @@
         """Copy this object to the `target` given.
 
         Returns the new name within the `target`.
-        
+
         Typically, the `target` is adapted to `IPasteTarget`.
         After the copy is added to the `target` container, publish
         an `IObjectCopied` event in the context of the target container.
@@ -388,26 +401,26 @@
 
     def _configureCopy(self, copy, target, new_name):
         """Configures the copied object before it is added to `target`.
-        
+
         `target` and `new_name` are provided as additional information.
-        
+
         By default, `copy.__parent__` and `copy.__name__` are set to ``None``.
-        
+
         Subclasses may override this method to perform additional
         configuration of the copied object.
         """
         copy.__parent__ = copy.__name__ = None
 
     def copyable(self):
-        '''Returns True if the object is copyable, otherwise False.'''
+        """Returns True if the object is copyable, otherwise False."""
         return True
 
     def copyableTo(self, target, name=None):
-        '''Say whether the object can be copied to the given `target`.
+        """Say whether the object can be copied to the given `target`.
 
         Returns ``True`` if it can be copied there. Otherwise, returns
         ``False``.
-        '''
+        """
         if name is None:
             name = self.context.__name__
         try:
@@ -417,22 +430,161 @@
         return True
 
 
+class ContainerItemRenamer(object):
+    """An IContainerItemRenamer adapter for containers.
+
+    This adapter uses IObjectMover to move an item within the same container
+    to a different name. We need to first setup an adapter for IObjectMover:
+
+      >>> from zope.app.tests import ztapi
+      >>> from zope.app.container.interfaces import IContained
+      >>> ztapi.provideAdapter(IContained, IObjectMover, ObjectMover)
+
+    To rename an item in a container, instantiate a ContainerItemRenamer
+    with the container:
+
+      >>> container = SampleContainer()
+      >>> renamer = ContainerItemRenamer(container)
+
+    For this example, we'll rename an item 'foo':
+
+      >>> from zope.app.container.contained import Contained
+      >>> foo = Contained()
+      >>> container['foo'] = foo
+      >>> container['foo'] is foo
+      True
+
+    to 'bar':
+
+      >>> renamer.renameItem('foo', 'bar')
+      >>> container['foo'] is foo
+      Traceback (most recent call last):
+      KeyError: 'foo'
+      >>> container['bar'] is foo
+      True
+
+    If the item being renamed isn't in the container, a NotFoundError is raised:
+
+      >>> renamer.renameItem('foo', 'bar') # doctest:+ELLIPSIS
+      Traceback (most recent call last):
+      NotFoundError: (<...SampleContainer...>, 'foo')
+
+    If the new item name already exists, a DuplicationError is raised:
+
+      >>> renamer.renameItem('bar', 'bar')
+      Traceback (most recent call last):
+      DuplicationError: bar is already in use
+
+    """
+
+    adapts(IContainer)
+
+    implements(IContainerItemRenamer)
+
+    def __init__(self, container):
+        self.container = container
+
+    def renameItem(self, oldName, newName):
+        object = self.container.get(oldName)
+        if object is None:
+            raise NotFoundError(self.container, oldName)
+        mover = IObjectMover(object)
+
+        if newName in self.container:
+            raise DuplicationError("%s is already in use" % newName)
+
+        mover.moveTo(self.container, newName)
+
+
+class OrderedContainerItemRenamer(ContainerItemRenamer):
+    """Renames items within an ordered container.
+
+    This renamer preserves the original order of the contained items.
+
+    To illustrate, we need to setup an IObjectMover, which is used in the
+    renaming:
+
+      >>> from zope.app.tests import ztapi
+      >>> from zope.app.container.interfaces import IContained
+      >>> ztapi.provideAdapter(IContained, IObjectMover, ObjectMover)
+
+    To rename an item in an ordered container, we instantiate a
+    OrderedContainerItemRenamer with the container:
+
+      >>> from zope.app.container.ordered import OrderedContainer
+      >>> container = OrderedContainer()
+      >>> renamer = OrderedContainerItemRenamer(container)
+
+    We'll add three items to the container:
+
+      >>> container['1'] = 'Item 1'
+      >>> container['2'] = 'Item 2'
+      >>> container['3'] = 'Item 3'
+      >>> container.items()
+      [('1', 'Item 1'), ('2', 'Item 2'), ('3', 'Item 3')]
+
+    When we rename one of the items:
+
+      >>> renamer.renameItem('1', 'I')
+
+    the order is preserved:
+
+      >>> container.items()
+      [('I', 'Item 1'), ('2', 'Item 2'), ('3', 'Item 3')]
+
+    Renaming the other two items also preserves the origina order:
+
+      >>> renamer.renameItem('2', 'II')
+      >>> renamer.renameItem('3', 'III')
+      >>> container.items()
+      [('I', 'Item 1'), ('II', 'Item 2'), ('III', 'Item 3')]
+
+    As with the standard renamer, trying to rename a non-existent item raises
+    an error:
+
+      >>> renamer.renameItem('IV', '4') # doctest:+ELLIPSIS
+      Traceback (most recent call last):
+      NotFoundError: (<...OrderedContainer...>, 'IV')
+
+    And if the new item name already exists, a DuplicationError is raised:
+
+      >>> renamer.renameItem('III', 'I')
+      Traceback (most recent call last):
+      DuplicationError: I is already in use
+
+    """
+
+    adapts(IOrderedContainer)
+
+    implements(IContainerItemRenamer)
+
+    def renameItem(self, oldName, newName):
+        order = list(self.container.keys())
+        super(OrderedContainerItemRenamer, self).renameItem(oldName, newName)
+        order[order.index(oldName)] = newName
+        self.container.updateOrder(order)
+
+
 class PrincipalClipboard(object):
-    '''Principal clipboard
+    """Principal clipboard
 
     Clipboard information consists on tuples of
     ``{'action':action, 'target':target}``.
-    '''
+    """
 
+    adapts(IAnnotations)
+
+    implements(IPrincipalClipboard)
+
     def __init__(self, annotation):
         self.context = annotation
 
     def clearContents(self):
-        '''Clear the contents of the clipboard'''
+        """Clear the contents of the clipboard"""
         self.context['clipboard'] = ()
 
     def addItems(self, action, targets):
-        '''Add new items to the clipboard'''
+        """Add new items to the clipboard"""
         contents = self.getContents()
         actions = []
         for target in targets:
@@ -440,25 +592,26 @@
         self.context['clipboard'] = contents + tuple(actions)
 
     def setContents(self, clipboard):
-        '''Replace the contents of the clipboard by the given value'''
+        """Replace the contents of the clipboard by the given value"""
         self.context['clipboard'] = clipboard
 
     def getContents(self):
-        '''Return the contents of the clipboard'''
+        """Return the contents of the clipboard"""
         return self.context.get('clipboard', ())
 
 
 def rename(container, oldid, newid):
-    object = container.get(oldid)
-    if object is None:
-        raise NotFoundError(container, oldid)
-    mover = IObjectMover(object)
+    """Renames an item with oldid in the container to newid.
 
-    if newid in container:
-        raise DuplicationError("name, %s, is already in use" % newid)
+    This function is deprecated. Use IContainerItemRenamer instead.
+    """
+    # BBB (remove in 3.3)
+    warnings.warn(
+        "rename is deprecated and will not be supported starting in "
+        "ZopeX3 3.3. Use IContainerItemRenamer(container).renameItem "
+        "instead.", DeprecationWarning)
+    IContainerItemRenamer(container).renameItem(oldid, newid)
 
-    if mover.moveable() and mover.moveableTo(container, newid):
-        mover.moveTo(container, newid)
 
 class ExampleContainer(SampleContainer):
     # Sample container used for examples in doc stringss in this module

Modified: Zope3/trunk/src/zope/app/copypastemove/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/copypastemove/configure.zcml	2005-02-10 21:11:09 UTC (rev 29108)
+++ Zope3/trunk/src/zope/app/copypastemove/configure.zcml	2005-02-10 21:48:46 UTC (rev 29109)
@@ -5,25 +5,22 @@
     >
 
   <adapter
-      factory="zope.app.copypastemove.ObjectMover"
-      provides="zope.app.copypastemove.interfaces.IObjectMover"
+      factory=".ObjectMover"
       permission="zope.ManageContent"
-      for="*"
       trusted="y"
       />
 
   <adapter
-      factory="zope.app.copypastemove.ObjectCopier"
-      provides="zope.app.copypastemove.interfaces.IObjectCopier"
+      factory=".ObjectCopier"
       permission="zope.ManageContent"
-      for="*"
       trusted="y"
       />
 
-  <adapter
-      factory="zope.app.copypastemove.PrincipalClipboard"
-      provides="zope.app.copypastemove.interfaces.IPrincipalClipboard"
-      for="zope.app.annotation.interfaces.IAnnotations"
-      />
+  <adapter factory=".ContainerItemRenamer" />
 
+  <adapter factory=".OrderedContainerItemRenamer" />
+
+  <adapter factory=".PrincipalClipboard" />
+
+
 </configure>

Modified: Zope3/trunk/src/zope/app/copypastemove/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/app/copypastemove/interfaces.py	2005-02-10 21:11:09 UTC (rev 29108)
+++ Zope3/trunk/src/zope/app/copypastemove/interfaces.py	2005-02-10 21:48:46 UTC (rev 29109)
@@ -20,23 +20,23 @@
 from zope.interface import Interface
 
 class IObjectMover(Interface):
-    '''Use `IObjectMover(obj)` to move an object somewhere.'''
+    """Use `IObjectMover(obj)` to move an object somewhere."""
 
     def moveTo(target, new_name=None):
-        '''Move this object to the target given.
+        """Move this object to the target given.
 
         Returns the new name within the target.
-        Typically, the target is adapted to `IPasteTarget`.'''
+        Typically, the target is adapted to `IPasteTarget`."""
 
     def moveable():
-        '''Returns ``True`` if the object is moveable, otherwise ``False``.'''
+        """Returns ``True`` if the object is moveable, otherwise ``False``."""
 
     def moveableTo(target, name=None):
-        '''Say whether the object can be moved to the given `target`.
+        """Say whether the object can be moved to the given `target`.
 
         Returns ``True`` if it can be moved there. Otherwise, returns
         ``False``.
-        '''
+        """
 
 class IObjectCopier(Interface):
 
@@ -52,31 +52,41 @@
         """
 
     def copyable():
-        '''Returns ``True`` if the object is copyable, otherwise ``False``.'''
+        """Returns ``True`` if the object is copyable, otherwise ``False``."""
 
     def copyableTo(target, name=None):
-        '''Say whether the object can be copied to the given `target`.
+        """Say whether the object can be copied to the given `target`.
 
         Returns ``True`` if it can be copied there. Otherwise, returns
         ``False``.
-        '''
+        """
 
+class IContainerItemRenamer(Interface):
+
+    def renameItem(oldName, newName):
+        """Renames an object in the container from oldName to newName.
+
+        Raises NotFoundError if oldName doesn't exist in the container.
+
+        Raises DuplicationError if newName is already used in the container.
+        """
+
 class IPrincipalClipboard(Interface):
-    '''Interface for adapters that store/retrieve clipboard information
+    """Interface for adapters that store/retrieve clipboard information
     for a principal.
 
     Clipboard information consists on tuples of
       ``{'action':action, 'target':target}``.
-    '''
+    """
 
     def clearContents():
-        '''Clear the contents of the clipboard'''
+        """Clear the contents of the clipboard"""
 
     def addItems(action, targets):
-        '''Add new items to the clipboard'''
+        """Add new items to the clipboard"""
 
     def setContents(clipboard):
-        '''Replace the contents of the clipboard by the given value'''
+        """Replace the contents of the clipboard by the given value"""
 
     def getContents():
-        '''Return the contents of the clipboard'''
+        """Return the contents of the clipboard"""

Modified: Zope3/trunk/src/zope/app/copypastemove/tests/test_rename.py
===================================================================
--- Zope3/trunk/src/zope/app/copypastemove/tests/test_rename.py	2005-02-10 21:11:09 UTC (rev 29108)
+++ Zope3/trunk/src/zope/app/copypastemove/tests/test_rename.py	2005-02-10 21:48:46 UTC (rev 29109)
@@ -15,61 +15,15 @@
 
 $Id$
 """
-from unittest import TestCase, TestSuite, main, makeSuite
+import unittest
 
 from zope.testing.doctestunit import DocTestSuite
 from zope.app.tests.placelesssetup import setUp, tearDown
-from zope.app.tests import ztapi
 
-from zope.exceptions import NotFoundError, DuplicationError
-from zope.app.traversing.api import traverse
-from zope.app.site.tests.placefulsetup import PlacefulSetup
-from zope.app.container.interfaces import IContainer
-from zope.app.copypastemove.interfaces import IObjectMover
-from zope.app.copypastemove import ObjectMover
-from zope.app.copypastemove import rename
-
-class File(object):
-    pass
-
-class RenameTest(PlacefulSetup, TestCase):
-
-    def setUp(self):
-        PlacefulSetup.setUp(self)
-        PlacefulSetup.buildFolders(self)
-        ztapi.provideAdapter(None, IObjectMover, ObjectMover)
-
-    def test_simplerename(self):
-        root = self.rootFolder
-        folder1 = traverse(root, 'folder1')
-        self.failIf('file1' in folder1)
-        folder1['file1'] = File()
-        rename(folder1, 'file1', 'my_file1')
-        self.failIf('file1' in folder1)
-        self.failUnless('my_file1' in folder1)
-
-    def test_renamenonexisting(self):
-        root = self.rootFolder
-        folder1 = traverse(root, 'folder1')
-        self.failIf('a_test_file' in folder1)
-        self.assertRaises(NotFoundError, rename, folder1, 'file1', 'my_file1')
-
-    def test_renamesamename(self):
-        root = self.rootFolder
-        folder1 = traverse(root, 'folder1')
-        self.failIf('file1' in folder1)
-        self.failIf('file2' in folder1)
-        folder1['file1'] = File()
-        folder1['file2'] = File()
-        self.assertRaises(DuplicationError, rename, folder1, 'file1', 'file2')
-
 def test_suite():
-    suite = makeSuite(RenameTest)
-    suite.addTest(
-        DocTestSuite('zope.app.copypastemove',
-                     setUp=setUp, tearDown=tearDown),
-        )
-    return suite
+    return unittest.TestSuite((
+        DocTestSuite('zope.app.copypastemove',setUp=setUp, tearDown=tearDown),
+        ))
 
 if __name__=='__main__':
-    main(defaultTest='test_suite')
+    unittest.main(defaultTest='test_suite')

Modified: Zope3/trunk/src/zope/app/ftp/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/ftp/__init__.py	2005-02-10 21:11:09 UTC (rev 29108)
+++ Zope3/trunk/src/zope/app/ftp/__init__.py	2005-02-10 21:48:46 UTC (rev 29109)
@@ -31,7 +31,8 @@
 from zope.event import notify
 from zope.app.event.objectevent import ObjectCreatedEvent
 from zope.app.dublincore.interfaces import IZopeDublinCore
-from zope.app.copypastemove import rename
+from zope.app.copypastemove.interfaces import IContainerItemRenamer
+from zope.app.container.interfaces import IContainer
 
 class FTPView(object):
     implements(IFTPPublisher)
@@ -154,8 +155,8 @@
         self.remove(name)
 
     def rename(self, old, new):
-        dir = IWriteDirectory(self.context, None)
-        rename(dir, old, new)
+        dir = IContainer(self.context, None)
+        IContainerItemRenamer(dir).renameItem(old, new)
 
     def _overwrite(self, name, instream, start=None, end=None, append=False):
         file = self._dir[name]

Modified: Zope3/trunk/src/zope/app/ftp/tests/test_ftpview.py
===================================================================
--- Zope3/trunk/src/zope/app/ftp/tests/test_ftpview.py	2005-02-10 21:11:09 UTC (rev 29108)
+++ Zope3/trunk/src/zope/app/ftp/tests/test_ftpview.py	2005-02-10 21:48:46 UTC (rev 29109)
@@ -19,7 +19,12 @@
 import datetime
 from StringIO import StringIO
 from unittest import TestCase, TestSuite, main, makeSuite
+
+from zope.interface import implements
+
 import zope.server.ftp.tests.demofs as demofs
+
+from zope.app.tests import ztapi
 from zope.app.filerepresentation.interfaces import IReadFile, IWriteFile
 from zope.app.filerepresentation.interfaces import IReadDirectory
 from zope.app.filerepresentation.interfaces import IWriteDirectory
@@ -28,14 +33,17 @@
 from zope.app.dublincore.interfaces import IZopeDublinCore
 from zope.app.ftp import FTPView
 from zope.app.tests.placelesssetup import PlacelessSetup
-from zope.interface import implements
 from zope.app.copypastemove.interfaces import IObjectMover
+from zope.app.copypastemove.interfaces import IContainerItemRenamer
+from zope.app.copypastemove import ContainerItemRenamer
 from zope.app.container.contained import setitem, Contained
+from zope.app.container.interfaces import IContainer
 
 class Directory(demofs.Directory, Contained):
 
     implements(IReadDirectory, IWriteDirectory, IFileFactory,
-               IDirectoryFactory, IZopeDublinCore, IObjectMover)
+               IDirectoryFactory, IZopeDublinCore, IObjectMover,
+               IContainer)
 
     modified = datetime.datetime(1990, 1,1)
 
@@ -54,7 +62,7 @@
 
     def moveableTo(self, target, name=None):
         return True
-    
+
     def __call__(self, name, content_type='', data=None):
         if data:
             r = File()
@@ -111,6 +119,8 @@
         root['f'] = File('contents of\nf')
         root['g'] = File('contents of\ng')
         self.__view = FTPView(root, None)
+        ztapi.provideAdapter(IContainer, IContainerItemRenamer,
+            ContainerItemRenamer)
 
     def test_type(self):
         self.assertEqual(self.__view.type('test'), 'd')



More information about the Zope3-Checkins mailing list