zope.copypastemove-3.8.0/000755 000766 000024 00000000000 11443645445 015312 5ustar00macstaff000000 000000 zope.copypastemove-3.8.0/CHANGES.txt000644 000766 000024 00000003774 11443645442 017133 0ustar00macstaff000000 000000 ======= CHANGES ======= 3.8.0 (2010-09-14) ------------------ - Added a test that makes sure that dublin core meta data of folder contents get updated when the folder gets copied. (Requires `zope.dublincore` 3.8 or above.) 3.7.0 (2010-09-14) ------------------ - Honor the name given by the ``IObjectMover`` in ``OrderedContainerItemRenamer.renameItem``. It now returns the new of the obejct, too. Thanks to Marius Gedminas for the patch, and to Justin Ryan for the test. Fixes https://bugs.launchpad.net/zope.copypastemove/+bug/98385. - Add a check for name and container if the namechooser computes a name which is the same as the current name. Fixes https://bugs.launchpad.net/zope.copypastemove/+bug/123532 - Remove use of ``zope.testing.doctestunit`` in favor of stdlib's ``doctest``. - Moved ``zope.copypastemove``-related tests from ``zope.container`` here. 3.6.0 (2009-12-16) ------------------ - Favor ``zope.principalannotation`` over its ``zope.app`` variant. - Avoid ``zope.app.component`` and testing dependencies. 3.5.2 (2009-08-15) ------------------ - Fix documentation for the ``IObjectCopier.copyTo`` method. - Add a missing dependency on ``zope.app.component``. 3.5.1 (2009-02-09) ------------------ - Use the new ``zope.copy`` package for ObjectCopier to provide pluggable copying mechanism that is not dependent on ``zope.location`` hardly. - Move the ``ItemNotFoundError`` exception to the interfaces module as it's part of public API. Old import still works as we actually use it where it was previously defined, however, the new import place is preferred. 3.5.0 (2009-01-31) ------------------ - Use ``zope.container`` instead of ``zope.app.container``. 3.4.1 (2009-01-26) ------------------ - Move the test dependencies to a ``test`` extra requirement. 3.4.0 (2007-09-28) ------------------ - No further changes since 3.4.0a1. 3.4.0a1 (2007-04-22) -------------------- - Initial release as a separate project, corresponds to ``zope.copypastemove`` from Zope 3.4.0a1 zope.copypastemove-3.8.0/COPYRIGHT.txt000644 000766 000024 00000000040 11443645442 017412 0ustar00macstaff000000 000000 Zope Foundation and Contributorszope.copypastemove-3.8.0/LICENSE.txt000644 000766 000024 00000004026 11443645442 017134 0ustar00macstaff000000 000000 Zope Public License (ZPL) Version 2.1 A copyright notice accompanies this license document that identifies the copyright holders. This license has been certified as open source. It has also been designated as GPL compatible by the Free Software Foundation (FSF). Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Names of the copyright holders must not be used to endorse or promote products derived from this software without prior written permission from the copyright holders. 4. The right to distribute this software or to use it for any purpose does not give you the right to use Servicemarks (sm) or Trademarks (tm) of the copyright holders. Use of them is covered by separate agreement with the copyright holders. 5. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. Disclaimer THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. zope.copypastemove-3.8.0/PKG-INFO000644 000766 000024 00000007155 11443645445 016417 0ustar00macstaff000000 000000 Metadata-Version: 1.0 Name: zope.copypastemove Version: 3.8.0 Summary: Copy, Paste and Move support for content components. Home-page: http://pypi.python.org/pypi/zope.copypastemove Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: Overview --------- This package provides Copy, Paste and Move support for content components in Zope. In particular, it defines the following interfaces for this kind of functionality: * ``IObjectMover``, * ``IObjectCopier``, * ``IContentItemRenamer``, * ``IPrincipalClipboard`` as well as standard implementations for containers and contained objects as known from the ``zope.container`` package. ======= CHANGES ======= 3.8.0 (2010-09-14) ------------------ - Added a test that makes sure that dublin core meta data of folder contents get updated when the folder gets copied. (Requires `zope.dublincore` 3.8 or above.) 3.7.0 (2010-09-14) ------------------ - Honor the name given by the ``IObjectMover`` in ``OrderedContainerItemRenamer.renameItem``. It now returns the new of the obejct, too. Thanks to Marius Gedminas for the patch, and to Justin Ryan for the test. Fixes https://bugs.launchpad.net/zope.copypastemove/+bug/98385. - Add a check for name and container if the namechooser computes a name which is the same as the current name. Fixes https://bugs.launchpad.net/zope.copypastemove/+bug/123532 - Remove use of ``zope.testing.doctestunit`` in favor of stdlib's ``doctest``. - Moved ``zope.copypastemove``-related tests from ``zope.container`` here. 3.6.0 (2009-12-16) ------------------ - Favor ``zope.principalannotation`` over its ``zope.app`` variant. - Avoid ``zope.app.component`` and testing dependencies. 3.5.2 (2009-08-15) ------------------ - Fix documentation for the ``IObjectCopier.copyTo`` method. - Add a missing dependency on ``zope.app.component``. 3.5.1 (2009-02-09) ------------------ - Use the new ``zope.copy`` package for ObjectCopier to provide pluggable copying mechanism that is not dependent on ``zope.location`` hardly. - Move the ``ItemNotFoundError`` exception to the interfaces module as it's part of public API. Old import still works as we actually use it where it was previously defined, however, the new import place is preferred. 3.5.0 (2009-01-31) ------------------ - Use ``zope.container`` instead of ``zope.app.container``. 3.4.1 (2009-01-26) ------------------ - Move the test dependencies to a ``test`` extra requirement. 3.4.0 (2007-09-28) ------------------ - No further changes since 3.4.0a1. 3.4.0a1 (2007-04-22) -------------------- - Initial release as a separate project, corresponds to ``zope.copypastemove`` from Zope 3.4.0a1 Platform: UNKNOWN Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Framework :: Zope3 zope.copypastemove-3.8.0/README.txt000644 000766 000024 00000000625 11443645442 017010 0ustar00macstaff000000 000000 Overview --------- This package provides Copy, Paste and Move support for content components in Zope. In particular, it defines the following interfaces for this kind of functionality: * ``IObjectMover``, * ``IObjectCopier``, * ``IContentItemRenamer``, * ``IPrincipalClipboard`` as well as standard implementations for containers and contained objects as known from the ``zope.container`` package. zope.copypastemove-3.8.0/bootstrap.py000644 000766 000024 00000003302 11443645442 017674 0ustar00macstaff000000 000000 ############################################################################## # # Copyright (c) 2006 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Bootstrap a buildout-based project Simply run this script in a directory containing a buildout.cfg. The script accepts buildout command-line options, so you can use the -c option to specify an alternate configuration file. """ import os, shutil, sys, tempfile, urllib2 tmpeggs = tempfile.mkdtemp() ez = {} exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' ).read() in ez ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) import pkg_resources cmd = 'from setuptools.command.easy_install import main; main()' if sys.platform == 'win32': cmd = '"%s"' % cmd # work around spawn lamosity on windows ws = pkg_resources.working_set assert os.spawnle( os.P_WAIT, sys.executable, sys.executable, '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout', dict(os.environ, PYTHONPATH= ws.find(pkg_resources.Requirement.parse('setuptools')).location ), ) == 0 ws.add_entry(tmpeggs) ws.require('zc.buildout') import zc.buildout.buildout zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap']) shutil.rmtree(tmpeggs) zope.copypastemove-3.8.0/buildout.cfg000644 000766 000024 00000000154 11443645442 017617 0ustar00macstaff000000 000000 [buildout] develop = . parts = test [test] recipe = zc.recipe.testrunner eggs = zope.copypastemove [test] zope.copypastemove-3.8.0/setup.cfg000644 000766 000024 00000000073 11443645445 017133 0ustar00macstaff000000 000000 [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 zope.copypastemove-3.8.0/setup.py000644 000766 000024 00000005053 11443645442 017024 0ustar00macstaff000000 000000 ############################################################################## # # Copyright (c) 2006 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## # This package is developed by the Zope Toolkit project, documented here: # http://docs.zope.org/zopetoolkit # When developing and releasing this package, please follow the documented # Zope Toolkit policies as described by this documentation. ############################################################################## version = '3.8.0' from setuptools import setup, find_packages long_description = (open('README.txt').read() + '\n\n' + open('CHANGES.txt').read()) setup(name='zope.copypastemove', version = version, url='http://pypi.python.org/pypi/zope.copypastemove', license='ZPL 2.1', author='Zope Foundation and Contributors', author_email='zope-dev@zope.org', description="Copy, Paste and Move support for content components.", long_description=long_description, classifiers=['Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: Zope Public License', 'Programming Language :: Python', 'Framework :: Zope3', ], packages=find_packages('src'), package_dir = {'': 'src'}, namespace_packages=['zope',], extras_require=dict( test=['zope.principalannotation', 'zope.testing', 'zope.traversing', 'zope.dublincore >= 3.8', ]), install_requires=['setuptools', 'zope.annotation', 'zope.component', 'zope.container', 'zope.copy', 'zope.event', 'zope.exceptions', 'zope.interface', 'zope.lifecycleevent', 'zope.location', ], include_package_data = True, zip_safe = False, ) zope.copypastemove-3.8.0/src/000755 000766 000024 00000000000 11443645445 016101 5ustar00macstaff000000 000000 zope.copypastemove-3.8.0/src/zope/000755 000766 000024 00000000000 11443645445 017056 5ustar00macstaff000000 000000 zope.copypastemove-3.8.0/src/zope.copypastemove.egg-info/000755 000766 000024 00000000000 11443645445 023445 5ustar00macstaff000000 000000 zope.copypastemove-3.8.0/src/zope.copypastemove.egg-info/PKG-INFO000644 000766 000024 00000007155 11443645444 024551 0ustar00macstaff000000 000000 Metadata-Version: 1.0 Name: zope.copypastemove Version: 3.8.0 Summary: Copy, Paste and Move support for content components. Home-page: http://pypi.python.org/pypi/zope.copypastemove Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: Overview --------- This package provides Copy, Paste and Move support for content components in Zope. In particular, it defines the following interfaces for this kind of functionality: * ``IObjectMover``, * ``IObjectCopier``, * ``IContentItemRenamer``, * ``IPrincipalClipboard`` as well as standard implementations for containers and contained objects as known from the ``zope.container`` package. ======= CHANGES ======= 3.8.0 (2010-09-14) ------------------ - Added a test that makes sure that dublin core meta data of folder contents get updated when the folder gets copied. (Requires `zope.dublincore` 3.8 or above.) 3.7.0 (2010-09-14) ------------------ - Honor the name given by the ``IObjectMover`` in ``OrderedContainerItemRenamer.renameItem``. It now returns the new of the obejct, too. Thanks to Marius Gedminas for the patch, and to Justin Ryan for the test. Fixes https://bugs.launchpad.net/zope.copypastemove/+bug/98385. - Add a check for name and container if the namechooser computes a name which is the same as the current name. Fixes https://bugs.launchpad.net/zope.copypastemove/+bug/123532 - Remove use of ``zope.testing.doctestunit`` in favor of stdlib's ``doctest``. - Moved ``zope.copypastemove``-related tests from ``zope.container`` here. 3.6.0 (2009-12-16) ------------------ - Favor ``zope.principalannotation`` over its ``zope.app`` variant. - Avoid ``zope.app.component`` and testing dependencies. 3.5.2 (2009-08-15) ------------------ - Fix documentation for the ``IObjectCopier.copyTo`` method. - Add a missing dependency on ``zope.app.component``. 3.5.1 (2009-02-09) ------------------ - Use the new ``zope.copy`` package for ObjectCopier to provide pluggable copying mechanism that is not dependent on ``zope.location`` hardly. - Move the ``ItemNotFoundError`` exception to the interfaces module as it's part of public API. Old import still works as we actually use it where it was previously defined, however, the new import place is preferred. 3.5.0 (2009-01-31) ------------------ - Use ``zope.container`` instead of ``zope.app.container``. 3.4.1 (2009-01-26) ------------------ - Move the test dependencies to a ``test`` extra requirement. 3.4.0 (2007-09-28) ------------------ - No further changes since 3.4.0a1. 3.4.0a1 (2007-04-22) -------------------- - Initial release as a separate project, corresponds to ``zope.copypastemove`` from Zope 3.4.0a1 Platform: UNKNOWN Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Framework :: Zope3 zope.copypastemove-3.8.0/src/zope.copypastemove.egg-info/SOURCES.txt000644 000766 000024 00000001464 11443645444 025335 0ustar00macstaff000000 000000 CHANGES.txt COPYRIGHT.txt LICENSE.txt README.txt bootstrap.py buildout.cfg setup.py src/zope/__init__.py src/zope.copypastemove.egg-info/PKG-INFO src/zope.copypastemove.egg-info/SOURCES.txt src/zope.copypastemove.egg-info/dependency_links.txt src/zope.copypastemove.egg-info/namespace_packages.txt src/zope.copypastemove.egg-info/not-zip-safe src/zope.copypastemove.egg-info/requires.txt src/zope.copypastemove.egg-info/top_level.txt src/zope/copypastemove/__init__.py src/zope/copypastemove/configure.zcml src/zope/copypastemove/interfaces.py src/zope/copypastemove/tests/__init__.py src/zope/copypastemove/tests/test_clipboard.py src/zope/copypastemove/tests/test_metadata.py src/zope/copypastemove/tests/test_objectcopier.py src/zope/copypastemove/tests/test_objectmover.py src/zope/copypastemove/tests/test_rename.pyzope.copypastemove-3.8.0/src/zope.copypastemove.egg-info/dependency_links.txt000644 000766 000024 00000000001 11443645444 027512 0ustar00macstaff000000 000000 zope.copypastemove-3.8.0/src/zope.copypastemove.egg-info/namespace_packages.txt000644 000766 000024 00000000005 11443645444 027772 0ustar00macstaff000000 000000 zope zope.copypastemove-3.8.0/src/zope.copypastemove.egg-info/not-zip-safe000644 000766 000024 00000000001 11443645443 025671 0ustar00macstaff000000 000000 zope.copypastemove-3.8.0/src/zope.copypastemove.egg-info/requires.txt000644 000766 000024 00000000343 11443645444 026044 0ustar00macstaff000000 000000 setuptools zope.annotation zope.component zope.container zope.copy zope.event zope.exceptions zope.interface zope.lifecycleevent zope.location [test] zope.principalannotation zope.testing zope.traversing zope.dublincore >= 3.8zope.copypastemove-3.8.0/src/zope.copypastemove.egg-info/top_level.txt000644 000766 000024 00000000005 11443645444 026171 0ustar00macstaff000000 000000 zope zope.copypastemove-3.8.0/src/zope/__init__.py000644 000766 000024 00000000070 11443645442 021161 0ustar00macstaff000000 000000 __import__('pkg_resources').declare_namespace(__name__) zope.copypastemove-3.8.0/src/zope/copypastemove/000755 000766 000024 00000000000 11443645445 021754 5ustar00macstaff000000 000000 zope.copypastemove-3.8.0/src/zope/copypastemove/__init__.py000644 000766 000024 00000046766 11443645442 024105 0ustar00macstaff000000 000000 ############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Copy, Paste and Move support for content components """ __docformat__ = 'restructuredtext' import zope.component from zope.interface import implements, Invalid from zope.exceptions import DuplicationError from zope.component import adapts from zope.copy import copy from zope.event import notify from zope.location.interfaces import ISublocations from zope.annotation.interfaces import IAnnotations from zope.annotation.interfaces import IAnnotations from zope.lifecycleevent import ObjectCopiedEvent from zope.copypastemove.interfaces import IObjectMover from zope.copypastemove.interfaces import IObjectCopier from zope.copypastemove.interfaces import IContainerItemRenamer from zope.copypastemove.interfaces import IPrincipalClipboard from zope.copypastemove.interfaces import ItemNotFoundError from zope.container.sample import SampleContainer from zope.container.interfaces import IContainer, IOrderedContainer from zope.container.interfaces import IContained from zope.container.interfaces import INameChooser from zope.container.constraints import checkObject class ObjectMover(object): """Adapter for moving objects between containers To use an object mover, pass a contained `object` to the class. The contained `object` should implement `IContained`. It should be contained in a container that has an adapter to `INameChooser`. >>> from zope.container.contained import Contained >>> ob = Contained() >>> container = ExampleContainer() >>> container[u'foo'] = ob >>> mover = ObjectMover(ob) In addition to moving objects, object movers can tell you if the object is movable: >>> mover.moveable() True which, at least for now, they always are. A better question to ask is whether we can move to a particular container. Right now, we can always move to a container of the same class: >>> container2 = ExampleContainer() >>> mover.moveableTo(container2) True >>> mover.moveableTo({}) Traceback (most recent call last): ... TypeError: Container is not a valid Zope container. Of course, once we've decided we can move an object, we can use the mover to do so: >>> mover.moveTo(container2) u'foo' >>> list(container) [] >>> list(container2) [u'foo'] >>> ob.__parent__ is container2 True We can also specify a name: >>> mover.moveTo(container2, u'bar') u'bar' >>> list(container2) [u'bar'] >>> ob.__parent__ is container2 True >>> ob.__name__ u'bar' But we may not use the same name given, if the name is already in use: >>> container2[u'splat'] = 1 >>> mover.moveTo(container2, u'splat') u'splat_' >>> l = list(container2) >>> l.sort() >>> l [u'splat', u'splat_'] >>> ob.__name__ u'splat_' If we try to move to an invalid container, we'll get an error: >>> mover.moveTo({}) Traceback (most recent call last): ... TypeError: Container is not a valid Zope container. Do a test for preconditions: >>> import zope.interface >>> import zope.schema >>> def preNoZ(container, name, ob): ... "Silly precondition example" ... if name.startswith("Z"): ... raise zope.interface.Invalid("Invalid name.") >>> class I1(zope.interface.Interface): ... def __setitem__(name, on): ... "Add an item" ... __setitem__.precondition = preNoZ >>> from zope.container.interfaces import IContainer >>> class C1(object): ... zope.interface.implements(I1, IContainer) ... def __repr__(self): ... return 'C1' >>> from zope.container.constraints import checkObject >>> container3 = C1() >>> mover.moveableTo(container3, 'ZDummy') False >>> mover.moveableTo(container3, 'newName') True And a test for constraints: >>> def con1(container): ... "silly container constraint" ... if not hasattr(container, 'x'): ... return False ... return True ... >>> class I2(zope.interface.Interface): ... __parent__ = zope.schema.Field(constraint=con1) ... >>> class constrainedObject(object): ... zope.interface.implements(I2) ... def __init__(self): ... self.__name__ = 'constrainedObject' ... >>> cO = constrainedObject() >>> mover2 = ObjectMover(cO) >>> mover2.moveableTo(container) False >>> container.x = 1 >>> mover2.moveableTo(container) True """ adapts(IContained) implements(IObjectMover) def __init__(self, object): self.context = object self.__parent__ = object # TODO: see if we can automate this def moveTo(self, target, new_name=None): """Move this object to the `target` given. Returns the new name within the `target` """ obj = self.context container = obj.__parent__ orig_name = obj.__name__ if new_name is None: new_name = orig_name checkObject(target, new_name, obj) if target is container and new_name == orig_name: # Nothing to do return chooser = INameChooser(target) new_name = chooser.chooseName(new_name, obj) if target is container and new_name == orig_name: # obstinate namechooser return target[new_name] = obj del container[orig_name] return new_name def moveable(self): """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. Returns ``True`` if it can be moved there. Otherwise, returns ``False``. """ if name is None: name = self.context.__name__ try: checkObject(target, name, self.context) except Invalid: return False return True class ObjectCopier(object): """Adapter for copying objects between containers To use an object copier, pass a contained `object` to the class. The contained `object` should implement `IContained`. It should be contained in a container that has an adapter to `INameChooser`. >>> from zope.container.contained import Contained >>> ob = Contained() >>> container = ExampleContainer() >>> container[u'foo'] = ob >>> copier = ObjectCopier(ob) In addition to moving objects, object copiers can tell you if the object is movable: >>> copier.copyable() True which, at least for now, they always are. A better question to ask is whether we can copy to a particular container. Right now, we can always copy to a container of the same class: >>> container2 = ExampleContainer() >>> copier.copyableTo(container2) True >>> copier.copyableTo({}) Traceback (most recent call last): ... TypeError: Container is not a valid Zope container. Of course, once we've decided we can copy an object, we can use the copier to do so: >>> copier.copyTo(container2) u'foo' >>> list(container) [u'foo'] >>> list(container2) [u'foo'] >>> ob.__parent__ is container True >>> container2[u'foo'] is ob False >>> container2[u'foo'].__parent__ is container2 True >>> container2[u'foo'].__name__ u'foo' We can also specify a name: >>> copier.copyTo(container2, u'bar') u'bar' >>> l = list(container2) >>> l.sort() >>> l [u'bar', u'foo'] >>> ob.__parent__ is container True >>> container2[u'bar'] is ob False >>> container2[u'bar'].__parent__ is container2 True >>> container2[u'bar'].__name__ u'bar' But we may not use the same name given, if the name is already in use: >>> copier.copyTo(container2, u'bar') u'bar_' >>> l = list(container2) >>> l.sort() >>> l [u'bar', u'bar_', u'foo'] >>> container2[u'bar_'].__name__ u'bar_' If we try to copy to an invalid container, we'll get an error: >>> copier.copyTo({}) Traceback (most recent call last): ... TypeError: Container is not a valid Zope container. Do a test for preconditions: >>> import zope.interface >>> import zope.schema >>> def preNoZ(container, name, ob): ... "Silly precondition example" ... if name.startswith("Z"): ... raise zope.interface.Invalid("Invalid name.") >>> class I1(zope.interface.Interface): ... def __setitem__(name, on): ... "Add an item" ... __setitem__.precondition = preNoZ >>> from zope.container.interfaces import IContainer >>> class C1(object): ... zope.interface.implements(I1, IContainer) ... def __repr__(self): ... return 'C1' >>> from zope.container.constraints import checkObject >>> container3 = C1() >>> copier.copyableTo(container3, 'ZDummy') False >>> copier.copyableTo(container3, 'newName') True And a test for constraints: >>> def con1(container): ... "silly container constraint" ... if not hasattr(container, 'x'): ... return False ... return True ... >>> class I2(zope.interface.Interface): ... __parent__ = zope.schema.Field(constraint=con1) ... >>> class constrainedObject(object): ... zope.interface.implements(I2) ... def __init__(self): ... self.__name__ = 'constrainedObject' ... >>> cO = constrainedObject() >>> copier2 = ObjectCopier(cO) >>> copier2.copyableTo(container) False >>> container.x = 1 >>> copier2.copyableTo(container) True """ adapts(IContained) implements(IObjectCopier) def __init__(self, object): self.context = object self.__parent__ = object # TODO: see if we can automate this def copyTo(self, target, new_name=None): """Copy this object to the `target` given. Returns the new name within the `target`. After the copy is created and before adding it to the target container, an `IObjectCopied` event is published. """ obj = self.context container = obj.__parent__ orig_name = obj.__name__ if new_name is None: new_name = orig_name checkObject(target, new_name, obj) chooser = INameChooser(target) new_name = chooser.chooseName(new_name, obj) new = copy(obj) notify(ObjectCopiedEvent(new, obj)) target[new_name] = new return new_name def copyable(self): """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`. Returns ``True`` if it can be copied there. Otherwise, returns ``False``. """ if name is None: name = self.context.__name__ try: checkObject(target, name, self.context) except Invalid: return False 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.container.interfaces import IContained >>> gsm = zope.component.getGlobalSiteManager() >>> gsm.registerAdapter(ObjectMover, (IContained, ), IObjectMover) 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.container.contained import Contained >>> foo = Contained() >>> container['foo'] = foo >>> container['foo'] is foo True to 'bar': >>> renamer.renameItem('foo', 'bar') u'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): ItemNotFoundError: (<...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): return self._renameItem(oldName, newName) def _renameItem(self, oldName, newName): object = self.container.get(oldName) if object is None: raise ItemNotFoundError(self.container, oldName) mover = IObjectMover(object) if newName in self.container: raise DuplicationError("%s is already in use" % newName) return 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.container.interfaces import IContained >>> gsm = zope.component.getGlobalSiteManager() >>> gsm.registerAdapter(ObjectMover, (IContained, ), IObjectMover) To rename an item in an ordered container, we instantiate a OrderedContainerItemRenamer with the container: >>> from zope.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') u'I' the order is preserved: >>> container.items() [(u'I', 'Item 1'), ('2', 'Item 2'), ('3', 'Item 3')] Renaming the other two items also preserves the origina order: >>> renamer.renameItem('2', 'II') u'II' >>> renamer.renameItem('3', 'III') u'III' >>> container.items() [(u'I', 'Item 1'), (u'II', 'Item 2'), (u'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): ItemNotFoundError: (<...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()) newName = self._renameItem(oldName, newName) order[order.index(oldName)] = newName self.container.updateOrder(order) return newName class PrincipalClipboard(object): """Principal clipboard Clipboard information consists of mappings 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""" self.context['clipboard'] = () def addItems(self, action, targets): """Add new items to the clipboard""" contents = self.getContents() actions = [] for target in targets: actions.append({'action':action, 'target':target}) self.context['clipboard'] = contents + tuple(actions) def setContents(self, clipboard): """Replace the contents of the clipboard by the given value""" self.context['clipboard'] = clipboard def getContents(self): """Return the contents of the clipboard""" return self.context.get('clipboard', ()) class ExampleContainer(SampleContainer): # Sample container used for examples in doc stringss in this module implements(INameChooser) def chooseName(self, name, ob): while name in self: name += '_' return name def dispatchToSublocations(object, event): """Dispatches an event to sublocations of a given object. This handler is used to dispatch copy events to sublocations. To illustrate, we'll first create a hierarchy of objects: >>> class L(object): ... def __init__(self, name): ... self.__name__ = name ... self.__parent__ = None ... def __repr__(self): ... return '%s(%s)' % (self.__class__.__name__, self.__name__) >>> class C(L): ... implements(ISublocations) ... def __init__(self, name, *subs): ... L.__init__(self, name) ... self.subs = subs ... for sub in subs: ... sub.__parent__ = self ... def sublocations(self): ... return self.subs >>> c = C(1, ... C(11, ... L(111), ... L(112), ... ), ... C(12, ... L(121), ... L(122), ... L(123), ... L(124), ... ), ... L(13), ... ) and a handler for copy events that records the objects it's seen: >>> seen = [] >>> def handler(ob, event): ... seen.append((ob, event.object)) Finally, we need to register our handler for copy events: >>> from zope.lifecycleevent.interfaces import IObjectCopiedEvent >>> gsm = zope.component.getGlobalSiteManager() >>> gsm.registerHandler(handler, [None, IObjectCopiedEvent]) and this function as a dispatcher: >>> gsm.registerHandler(dispatchToSublocations, ... [None, IObjectCopiedEvent]) When we notify that our root object has been copied: >>> notify(ObjectCopiedEvent(c, L(''))) we see that our handler has seen all of the subobjects: >>> seenreprs = map(repr, seen) >>> seenreprs.sort() >>> seenreprs #doctest: +NORMALIZE_WHITESPACE ['(C(1), C(1))', '(C(11), C(1))', '(C(12), C(1))', '(L(111), C(1))', '(L(112), C(1))', '(L(121), C(1))', '(L(122), C(1))', '(L(123), C(1))', '(L(124), C(1))', '(L(13), C(1))'] """ subs = ISublocations(object, None) if subs is not None: for sub in subs.sublocations(): for ignored in zope.component.subscribers((sub, event), None): pass # They do work in the adapter fetch zope.copypastemove-3.8.0/src/zope/copypastemove/configure.zcml000644 000766 000024 00000001263 11443645442 024623 0ustar00macstaff000000 000000 zope.copypastemove-3.8.0/src/zope/copypastemove/interfaces.py000644 000766 000024 00000005603 11443645442 024452 0ustar00macstaff000000 000000 ############################################################################## # # Copyright (c) 2003 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Copy and Move support """ __docformat__ = 'restructuredtext' from zope.interface import Interface, implements class IObjectMover(Interface): """Use `IObjectMover(obj)` to move an object somewhere.""" def moveTo(target, new_name=None): """Move this object to the target given. Returns the new name within the target. """ def moveable(): """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`. Returns ``True`` if it can be moved there. Otherwise, returns ``False``. """ class IObjectCopier(Interface): def copyTo(target, new_name=None): """Copy this object to the `target` given. Returns the new name within the `target`. After the copy is created and before adding it to the target container, an `IObjectCopied` event is published. """ def copyable(): """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`. 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 ItemNotFoundError 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 for a principal. Clipboard information consists of mappings of ``{'action':action, 'target':target}``. """ def clearContents(): """Clear the contents of the clipboard""" def addItems(action, targets): """Add new items to the clipboard""" def setContents(clipboard): """Replace the contents of the clipboard by the given value""" def getContents(): """Return the contents of the clipboard""" class IItemNotFoundError(Interface): pass class ItemNotFoundError(LookupError): implements(IItemNotFoundError) zope.copypastemove-3.8.0/src/zope/copypastemove/tests/000755 000766 000024 00000000000 11443645445 023116 5ustar00macstaff000000 000000 zope.copypastemove-3.8.0/src/zope/copypastemove/tests/__init__.py000644 000766 000024 00000000017 11443645442 025222 0ustar00macstaff000000 000000 # Import this. zope.copypastemove-3.8.0/src/zope/copypastemove/tests/test_clipboard.py000644 000766 000024 00000006663 11443645442 026476 0ustar00macstaff000000 000000 ############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Clipboard tests """ import unittest import zope.component from zope.annotation.interfaces import IAnnotations from zope.component.testing import PlacelessSetup from zope.principalannotation.utility import PrincipalAnnotationUtility from zope.principalannotation.interfaces import IPrincipalAnnotationUtility from zope.copypastemove import PrincipalClipboard from zope.copypastemove.interfaces import IPrincipalClipboard class PrincipalStub(object): def __init__(self, id): self.id = id class PrincipalClipboardTest(PlacelessSetup, unittest.TestCase): def setUp(self): gsm = zope.component.getGlobalSiteManager() gsm.registerAdapter(PrincipalClipboard, (IAnnotations, ), IPrincipalClipboard) gsm.registerUtility(PrincipalAnnotationUtility(), IPrincipalAnnotationUtility) def testAddItems(self): user = PrincipalStub('srichter') annotationutil = zope.component.getUtility(IPrincipalAnnotationUtility) annotations = annotationutil.getAnnotations(user) clipboard = IPrincipalClipboard(annotations) clipboard.addItems('move', ['bla', 'bla/foo', 'bla/bar']) expected = ({'action':'move', 'target':'bla'}, {'action':'move', 'target':'bla/foo'}, {'action':'move', 'target':'bla/bar'}) self.failUnless(clipboard.getContents() == expected) clipboard.addItems('copy', ['bla']) expected = expected + ({'action':'copy', 'target':'bla'},) self.failUnless(clipboard.getContents() == expected) def testSetContents(self): user = PrincipalStub('srichter') annotationutil = zope.component.getUtility(IPrincipalAnnotationUtility) annotations = annotationutil.getAnnotations(user) clipboard = IPrincipalClipboard(annotations) expected = ({'action':'move', 'target':'bla'}, {'action':'move', 'target':'bla/foo'}, {'action':'move', 'target':'bla/bar'}) clipboard.setContents(expected) self.failUnless(clipboard.getContents() == expected) clipboard.addItems('copy', ['bla']) expected = expected + ({'action':'copy', 'target':'bla'},) self.failUnless(clipboard.getContents() == expected) def testClearContents(self): user = PrincipalStub('srichter') annotationutil = zope.component.getUtility(IPrincipalAnnotationUtility) annotations = annotationutil.getAnnotations(user) clipboard = IPrincipalClipboard(annotations) clipboard.clearContents() self.failUnless(clipboard.getContents() == ()) def test_suite(): return unittest.TestSuite(( unittest.makeSuite(PrincipalClipboardTest), )) if __name__=='__main__': unittest.main(defaultTest='test_suite') zope.copypastemove-3.8.0/src/zope/copypastemove/tests/test_metadata.py000644 000766 000024 00000007272 11443645442 026314 0ustar00macstaff000000 000000 ############################################################################## # # Copyright (c) 2010 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Object copier metadata tests""" import datetime import unittest import zope.annotation import zope.annotation.attribute import zope.component import zope.container.contained import zope.container.interfaces import zope.container.sample import zope.container.testing import zope.copypastemove import zope.dublincore.testing import zope.dublincore.timeannotators import zope.lifecycleevent.interfaces import zope.location.interfaces import zope.traversing.api class CopyCreationTimeTest(zope.container.testing.ContainerPlacefulSetup, unittest.TestCase): def setUp(self): super(CopyCreationTimeTest, self).setUp() # We need a folder hierarchy for copying: self.buildFolders() # We need the default zope.dublincore adapters: zope.dublincore.testing.setUpDublinCore() # And the created annotator for the ObjectCopiedEvent zope.component.provideHandler( zope.dublincore.timeannotators.CreatedAnnotator, [zope.lifecycleevent.interfaces.IObjectCopiedEvent]) zope.component.provideHandler( zope.dublincore.timeannotators.CreatedAnnotator, [None, zope.lifecycleevent.interfaces.IObjectCopiedEvent]) # The metadata are stored in annotations on the container: zope.interface.classImplements( zope.container.sample.SampleContainer, zope.annotation.IAttributeAnnotatable) zope.component.provideAdapter( zope.annotation.attribute.AttributeAnnotations) # We need the dispatch the copied event to the sub locations: zope.component.provideHandler( zope.copypastemove.dispatchToSublocations, [None, zope.lifecycleevent.interfaces.IObjectCopiedEvent]) zope.component.provideAdapter( zope.container.contained.ContainerSublocations, [zope.container.interfaces.IReadContainer], zope.location.interfaces.ISublocations) def test_copy(self): from zope.dublincore.interfaces import IZopeDublinCore from zope.traversing.api import traverse # Neither the original folder nor one of its subfolders have a # creation date as there was no event on creation: folder = traverse(self.rootFolder, 'folder1') self.assertTrue(IZopeDublinCore(folder).created is None) subfolder = traverse(self.rootFolder, 'folder1/folder1_1') self.assertTrue(IZopeDublinCore(subfolder).created is None) # After copying the folder, it has a creation date: copier = zope.copypastemove.ObjectCopier(folder) copier.copyTo(self.rootFolder, 'folder-copy') folder_copy = traverse(self.rootFolder, 'folder-copy') self.assertTrue(isinstance(IZopeDublinCore(folder_copy).created, datetime.datetime)) # The subfolder has a creation date, too: subfolder_copy = traverse(self.rootFolder, 'folder-copy/folder1_1') self.assertTrue(isinstance(IZopeDublinCore(subfolder_copy).created, datetime.datetime)) zope.copypastemove-3.8.0/src/zope/copypastemove/tests/test_objectcopier.py000644 000766 000024 00000015607 11443645442 027205 0ustar00macstaff000000 000000 ############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Object Copier Tests """ import unittest import doctest import zope.component from zope.traversing.api import traverse from zope.component.eventtesting import clearEvents from zope.component.eventtesting import getEvents from zope.copypastemove import ObjectCopier from zope.copypastemove.interfaces import IObjectCopier from zope.container import testing class File(object): pass def test_copy_events(): """ Prepare an IObjectCopier:: >>> from zope import component >>> component.provideAdapter(ObjectCopier, (None,), IObjectCopier) We set things up in a root folder:: >>> from zope.container.sample import SampleContainer >>> root = SampleContainer() Prepare some objects:: >>> folder = SampleContainer() >>> root[u'foo'] = File() >>> root[u'folder'] = folder >>> list(folder.keys()) [] >>> foo = traverse(root, 'foo') # wrap in ContainedProxy Now make a copy:: >>> clearEvents() >>> copier = IObjectCopier(foo) >>> copier.copyTo(folder, u'bar') u'bar' Check that the copy has been done:: >>> list(folder.keys()) [u'bar'] Check what events have been sent:: >>> events = getEvents() >>> [event.__class__.__name__ for event in events] ['ObjectCopiedEvent', 'ObjectAddedEvent', 'ContainerModifiedEvent'] Check that the ObjectCopiedEvent includes the correct data:: >>> events[0].object is folder[u'bar'] True >>> events[0].original is root[u'foo'] True """ class ObjectCopierTest(testing.ContainerPlacefulSetup, unittest.TestCase): def setUp(self): testing.ContainerPlacefulSetup.setUp(self) self.buildFolders() zope.component.provideAdapter(ObjectCopier, (None,), IObjectCopier) def test_copytosame(self): root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() file = traverse(root, 'folder1/file1') copier = IObjectCopier(file) copier.copyTo(container, 'file1') self.failUnless('file1' in container) self.failUnless('file1-2' in container) def test_copytosamewithnewname(self): root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() file = traverse(root, 'folder1/file1') copier = IObjectCopier(file) copier.copyTo(container, 'file2') self.failUnless('file1' in container) self.failUnless('file2' in container) def test_copytoother(self): root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() target = traverse(root, 'folder2') file = traverse(root, 'folder1/file1') copier = IObjectCopier(file) copier.copyTo(target, 'file1') self.failUnless('file1' in container) self.failUnless('file1' in target) def test_copytootherwithnewname(self): root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() target = traverse(root, 'folder2') file = traverse(root, 'folder1/file1') copier = IObjectCopier(file) copier.copyTo(target, 'file2') self.failUnless('file1' in container) self.failUnless('file2' in target) def test_copytootherwithnamecollision(self): root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() target = traverse(root, 'folder2') target['file1'] = File() file = traverse(root, 'folder1/file1') copier = IObjectCopier(file) copier.copyTo(target, 'file1') # we do it twice, just to test auto-name generation copier.copyTo(target, 'file1') self.failUnless('file1' in container) self.failUnless('file1' in target) self.failUnless('file1-2' in target) self.failUnless('file1-3' in target) def test_copyable(self): root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() file = traverse(root, 'folder1/file1') copier = IObjectCopier(file) self.failUnless(copier.copyable()) def test_copyableTo(self): # A file should be copyable to a folder that has an # object with the same id. root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() file = traverse(root, 'folder1/file1') copier = IObjectCopier(file) self.failUnless(copier.copyableTo(container, 'file1')) def test_copyfoldertosibling(self): root = self.rootFolder target = traverse(root, '/folder2') source = traverse(root, '/folder1/folder1_1') copier = IObjectCopier(source) copier.copyTo(target) self.failUnless('folder1_1' in target) def test_copyfoldertosame(self): root = self.rootFolder target = traverse(root, '/folder1') source = traverse(root, '/folder1/folder1_1') copier = IObjectCopier(source) copier.copyTo(target) self.failUnless('folder1_1' in target) def test_copyfoldertosame2(self): root = self.rootFolder target = traverse(root, '/folder1/folder1_1') source = traverse(root, '/folder1/folder1_1/folder1_1_1') copier = IObjectCopier(source) copier.copyTo(target) self.failUnless('folder1_1_1' in target) def test_copyfolderfromroot(self): root = self.rootFolder target = traverse(root, '/folder2') source = traverse(root, '/folder1') copier = IObjectCopier(source) copier.copyTo(target) self.failUnless('folder1' in target) def test_copyfolderfromroot2(self): root = self.rootFolder target = traverse(root, '/folder2/folder2_1/folder2_1_1') source = traverse(root, '/folder1') copier = IObjectCopier(source) copier.copyTo(target) self.failUnless('folder1' in target) def test_suite(): return unittest.TestSuite(( unittest.makeSuite(ObjectCopierTest), doctest.DocTestSuite( setUp=testing.ContainerPlacefulSetup().setUp, tearDown=testing.ContainerPlacefulSetup().tearDown), )) zope.copypastemove-3.8.0/src/zope/copypastemove/tests/test_objectmover.py000644 000766 000024 00000016264 11443645442 027054 0ustar00macstaff000000 000000 ############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Object Mover Tests """ import unittest import doctest import zope.component from zope.traversing.api import traverse from zope.component.eventtesting import clearEvents from zope.component.eventtesting import getEvents from zope.copypastemove import ObjectMover from zope.copypastemove.interfaces import IObjectMover from zope.container import testing class File(object): pass def test_move_events(): """ We need a root folder:: >>> from zope.container.sample import SampleContainer >>> root = SampleContainer() Prepare the setup:: >>> from zope import component >>> component.provideAdapter(ObjectMover, (None,), IObjectMover) Prepare some objects:: >>> folder = SampleContainer() >>> root[u'foo'] = File() >>> root[u'folder'] = folder >>> list(folder.keys()) [] >>> foo = traverse(root, 'foo') # wrap in ContainedProxy Now move it:: >>> clearEvents() >>> mover = IObjectMover(foo) >>> mover.moveableTo(folder) True >>> mover.moveTo(folder, u'bar') u'bar' Check that the move has been done:: >>> list(root.keys()) [u'folder'] >>> list(folder.keys()) [u'bar'] Check what events have been sent:: >>> events = getEvents() >>> [event.__class__.__name__ for event in events] ['ObjectMovedEvent', 'ContainerModifiedEvent', 'ContainerModifiedEvent'] Verify that the ObjectMovedEvent includes the correct data:: >>> events[0].oldName, events[0].newName (u'foo', u'bar') >>> events[0].oldParent is root True >>> events[0].newParent is folder True Let's look the other events: >>> events[1].object is folder True >>> events[2].object is root True """ class ObjectMoverTest(testing.ContainerPlacefulSetup, unittest.TestCase): def setUp(self): testing.ContainerPlacefulSetup.setUp(self) self.buildFolders() zope.component.provideAdapter(ObjectMover, (None,), ) def test_movetosame(self): # Should be a noop, because "moving" to same location root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() file = traverse(root, 'folder1/file1') mover = IObjectMover(file) mover.moveTo(container, 'file1') self.failUnless('file1' in container) self.assertEquals(len(container), 2) def test_movetosamewithnewname(self): root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() file = traverse(root, 'folder1/file1') mover = IObjectMover(file) mover.moveTo(container, 'file2') self.failIf('file1' in container) self.failUnless('file2' in container) def test_movetoother(self): root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() target = traverse(root, 'folder2') file = traverse(root, 'folder1/file1') mover = IObjectMover(file) mover.moveTo(target, 'file1') self.failIf('file1' in container) self.failUnless('file1' in target) def test_movetootherwithnewname(self): root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() target = traverse(root, 'folder2') file = traverse(root, 'folder1/file1') mover = IObjectMover(file) mover.moveTo(target, 'file2') self.failIf('file1' in container) self.failUnless('file2' in target) def test_movetootherwithnamecollision(self): root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() target = traverse(root, 'folder2') target['file1'] = File() file = traverse(root, 'folder1/file1') mover = IObjectMover(file) mover.moveTo(target, 'file1') self.failIf('file1' in container) self.failUnless('file1' in target) self.failUnless('file1-2' in target) def test_moveable(self): root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() file = traverse(root, 'folder1/file1') mover = IObjectMover(file) self.failUnless(mover.moveable()) def test_moveableTo(self): # A file should be moveable to a folder that has an # object with the same id. root = self.rootFolder container = traverse(root, 'folder1') container['file1'] = File() file = traverse(root, 'folder1/file1') mover = IObjectMover(file) self.failUnless(mover.moveableTo(container, 'file1')) def test_movefoldertosibling(self): root = self.rootFolder target = traverse(root, '/folder2') source = traverse(root, '/folder1/folder1_1') mover = IObjectMover(source) mover.moveTo(target) self.failUnless('folder1_1' in target) def test_movefoldertosame(self): # Should be a noop, because "moving" to same location root = self.rootFolder target = traverse(root, '/folder1') source = traverse(root, '/folder1/folder1_1') mover = IObjectMover(source) mover.moveTo(target) self.failUnless('folder1_1' in target) self.assertEquals(len(target), 1) def test_movefoldertosame2(self): # Should be a noop, because "moving" to same location root = self.rootFolder target = traverse(root, '/folder1/folder1_1') source = traverse(root, '/folder1/folder1_1/folder1_1_1') mover = IObjectMover(source) mover.moveTo(target) self.failUnless('folder1_1_1' in target) self.assertEquals(len(target), 1) def test_movefolderfromroot(self): root = self.rootFolder target = traverse(root, '/folder2') source = traverse(root, '/folder1') mover = IObjectMover(source) mover.moveTo(target) self.failUnless('folder1' in target) def test_movefolderfromroot2(self): root = self.rootFolder target = traverse(root, '/folder2/folder2_1/folder2_1_1') source = traverse(root, '/folder1') mover = IObjectMover(source) mover.moveTo(target) self.failUnless('folder1' in target) def test_suite(): return unittest.TestSuite(( unittest.makeSuite(ObjectMoverTest), doctest.DocTestSuite( setUp=testing.ContainerPlacefulSetup().setUp, tearDown=testing.ContainerPlacefulSetup().tearDown), )) zope.copypastemove-3.8.0/src/zope/copypastemove/tests/test_rename.py000644 000766 000024 00000010220 11443645442 025766 0ustar00macstaff000000 000000 ############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Test renaming of components """ import unittest from doctest import DocTestSuite from zope.component import testing, eventtesting, provideAdapter, adapts from zope.container.testing import PlacelessSetup, ContainerPlacefulSetup from zope.copypastemove import ContainerItemRenamer, ObjectMover from zope.copypastemove.interfaces import IContainerItemRenamer from zope.container.contained import Contained, NameChooser from zope.container.sample import SampleContainer class TestContainer(SampleContainer): pass class ObstinateNameChooser(NameChooser): adapts(TestContainer) def chooseName(self, name, ob): return u'foobar' class RenamerTest(ContainerPlacefulSetup, unittest.TestCase): def setUp(self): ContainerPlacefulSetup.setUp(self) provideAdapter(ObjectMover) provideAdapter(ContainerItemRenamer) provideAdapter(ObstinateNameChooser) def test_obstinatenamechooser(self): container = TestContainer() container[u'foobar'] = Contained() renamer = IContainerItemRenamer(container) renamer.renameItem(u'foobar', u'newname') self.assertEqual(list(container), [u'foobar']) container_setup = PlacelessSetup() def setUp(test): testing.setUp() eventtesting.setUp() container_setup.setUp() def doctest_namechooser_rename_preserve_order(): """Test for OrderedContainerItemRenamer.renameItem This is a regression test for http://www.zope.org/Collectors/Zope3-dev/658 Also: https://bugs.launchpad.net/zope.copypastemove/+bug/98385 >>> from zope.component import adapts, provideAdapter >>> from zope.copypastemove import ObjectMover >>> provideAdapter(ObjectMover) There's an ordered container >>> from zope.container.ordered import OrderedContainer >>> container = OrderedContainer() >>> from zope.container.contained import Contained >>> class Obj(Contained): ... def __init__(self, title): ... self.title = title ... def __repr__(self): ... return self.title >>> container['foo'] = Obj('Foo') >>> container['bar'] = Obj('Bar') >>> container['baz'] = Obj('Baz') with a custom name chooser >>> from zope.interface import implements, Interface >>> from zope.container.interfaces import INameChooser >>> class IMyContainer(Interface): pass >>> class MyNameChooser(object): ... adapts(IMyContainer) ... implements(INameChooser) ... def __init__(self, container): ... self.container = container ... def chooseName(self, name, obj): ... return name.encode('rot-13') >>> provideAdapter(MyNameChooser) >>> from zope.interface import alsoProvides >>> alsoProvides(container, IMyContainer) OrderedContainerItemRenamer renames and preserves the order of items >>> from zope.copypastemove import OrderedContainerItemRenamer >>> renamer = OrderedContainerItemRenamer(container) >>> renamer.renameItem('bar', 'quux') 'dhhk' >>> list(container.keys()) ['foo', 'dhhk', 'baz'] >>> list(container.values()) [Foo, Bar, Baz] """ def test_suite(): return unittest.TestSuite(( unittest.makeSuite(RenamerTest), DocTestSuite('zope.copypastemove', setUp=setUp, tearDown=testing.tearDown), DocTestSuite(setUp=setUp, tearDown=testing.tearDown), ))