zope.copypastemove-4.0.0a1/0000775000000000000000000000000012357561405014317 5ustar rootrootzope.copypastemove-4.0.0a1/bootstrap.py0000664000000000000000000001311112112560404016666 0ustar rootroot############################################################################## # # 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 from optparse import OptionParser tmpeggs = tempfile.mkdtemp() usage = '''\ [DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] Bootstraps a buildout-based project. Simply run this script in a directory containing a buildout.cfg, using the Python that you want bin/buildout to use. Note that by using --setup-source and --download-base to point to local resources, you can keep this script from going over the network. ''' parser = OptionParser(usage=usage) parser.add_option("-v", "--version", help="use a specific zc.buildout version") parser.add_option("-t", "--accept-buildout-test-releases", dest='accept_buildout_test_releases', action="store_true", default=False, help=("Normally, if you do not specify a --version, the " "bootstrap script and buildout gets the newest " "*final* versions of zc.buildout and its recipes and " "extensions for you. If you use this flag, " "bootstrap and buildout will get the newest releases " "even if they are alphas or betas.")) parser.add_option("-c", "--config-file", help=("Specify the path to the buildout configuration " "file to be used.")) parser.add_option("-f", "--find-links", help=("Specify a URL to search for buildout releases")) options, args = parser.parse_args() ###################################################################### # load/install distribute to_reload = False try: import pkg_resources, setuptools if not hasattr(pkg_resources, '_distribute'): to_reload = True raise ImportError except ImportError: ez = {} try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen exec(urlopen('http://python-distribute.org/distribute_setup.py').read(), ez) setup_args = dict(to_dir=tmpeggs, download_delay=0, no_fake=True) ez['use_setuptools'](**setup_args) if to_reload: reload(pkg_resources) import pkg_resources # This does not (always?) update the default working set. We will # do it. for path in sys.path: if path not in pkg_resources.working_set.entries: pkg_resources.working_set.add_entry(path) ###################################################################### # Install buildout ws = pkg_resources.working_set cmd = [sys.executable, '-c', 'from setuptools.command.easy_install import main; main()', '-mZqNxd', tmpeggs] find_links = os.environ.get( 'bootstrap-testing-find-links', options.find_links or ('http://downloads.buildout.org/' if options.accept_buildout_test_releases else None) ) if find_links: cmd.extend(['-f', find_links]) distribute_path = ws.find( pkg_resources.Requirement.parse('distribute')).location requirement = 'zc.buildout' version = options.version if version is None and not options.accept_buildout_test_releases: # Figure out the most recent final version of zc.buildout. import setuptools.package_index _final_parts = '*final-', '*final' def _final_version(parsed_version): for part in parsed_version: if (part[:1] == '*') and (part not in _final_parts): return False return True index = setuptools.package_index.PackageIndex( search_path=[distribute_path]) if find_links: index.add_find_links((find_links,)) req = pkg_resources.Requirement.parse(requirement) if index.obtain(req) is not None: best = [] bestv = None for dist in index[req.project_name]: distv = dist.parsed_version if _final_version(distv): if bestv is None or distv > bestv: best = [dist] bestv = distv elif distv == bestv: best.append(dist) if best: best.sort() version = best[-1].version if version: requirement = '=='.join((requirement, version)) cmd.append(requirement) import subprocess if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=distribute_path)) != 0: raise Exception( "Failed to execute command:\n%s", repr(cmd)[1:-1]) ###################################################################### # Import and run buildout ws.add_entry(tmpeggs) ws.require(requirement) import zc.buildout.buildout if not [a for a in args if '=' not in a]: args.append('bootstrap') # if -c was provided, we push it back into args for buildout' main function if options.config_file is not None: args[0:0] = ['-c', options.config_file] zc.buildout.buildout.main(args) shutil.rmtree(tmpeggs) zope.copypastemove-4.0.0a1/CHANGES.txt0000664000000000000000000000472312112560404016121 0ustar rootroot======= CHANGES ======= 4.0.0a1 (2013-02-24) -------------------- - Added support for Python 3.3. - Replaced deprecated ``zope.component.adapts`` usage with equivalent ``zope.component.adapter`` decorator. - Replaced deprecated ``zope.interface.implements`` usage with equivalent ``zope.interface.implementer`` decorator. - Dropped support for Python 2.4 and 2.5. - Include zcml dependencies in configure.zcml, require the necessary packages via a zcml extra, added tests for zcml. 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-4.0.0a1/buildout.cfg0000664000000000000000000000061312112560404016612 0ustar rootroot[buildout] develop = . find-links = ${buildout:directory}/ZODB-4.0.0dev.tar.gz parts = test versions = versions [test] recipe = zc.recipe.testrunner eggs = zope.copypastemove [test,zcml] [versions] ZODB = 4.0.0dev zope.container = 4.0.0a2 zope.i18n = 4.0.0a3 zope.principalannotation = 4.0.0a1 zope.publisher = 4.0.0a2 zope.security = 4.0.0a3 zope.site = 4.0.0a1 zope.traversing = 4.0.0a2 zope.copypastemove-4.0.0a1/tox.ini0000664000000000000000000000062312112560404015616 0ustar rootroot[tox] envlist = py26,py27,py33 [testenv] commands = python setup.py test -q deps = {toxinidir}/ZODB-4.0.0dev.tar.gz zope.annotation zope.component zope.container zope.copy zope.dublincore zope.event zope.exceptions zope.interface zope.lifecycleevent zope.location zope.principalannotation zope.testing zope.testrunner zope.traversing zope.copypastemove-4.0.0a1/src/0000775000000000000000000000000012357561405015106 5ustar rootrootzope.copypastemove-4.0.0a1/src/zope/0000775000000000000000000000000012357561405016063 5ustar rootrootzope.copypastemove-4.0.0a1/src/zope/__init__.py0000664000000000000000000000007012112560404020154 0ustar rootroot__import__('pkg_resources').declare_namespace(__name__) zope.copypastemove-4.0.0a1/src/zope/copypastemove/0000775000000000000000000000000012357561405020761 5ustar rootrootzope.copypastemove-4.0.0a1/src/zope/copypastemove/configure.zcml0000664000000000000000000000154112112560404023615 0ustar rootroot zope.copypastemove-4.0.0a1/src/zope/copypastemove/__init__.py0000664000000000000000000004667212112560404023074 0ustar rootroot############################################################################## # # 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 implementer, Invalid from zope.exceptions import DuplicationError from zope.component import adapter 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 @adapter(IContained) @implementer(IObjectMover) 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 >>> @zope.interface.implementer(I1, IContainer) ... class C1(object): ... 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) ... >>> @zope.interface.implementer(I2) ... class constrainedObject(object): ... def __init__(self): ... self.__name__ = 'constrainedObject' ... >>> cO = constrainedObject() >>> mover2 = ObjectMover(cO) >>> mover2.moveableTo(container) False >>> container.x = 1 >>> mover2.moveableTo(container) True """ 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 @adapter(IContained) @implementer(IObjectCopier) 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 >>> @zope.interface.implementer(I1, IContainer) ... class C1(object): ... 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) ... >>> @zope.interface.implementer(I2) ... class constrainedObject(object): ... def __init__(self): ... self.__name__ = 'constrainedObject' ... >>> cO = constrainedObject() >>> copier2 = ObjectCopier(cO) >>> copier2.copyableTo(container) False >>> container.x = 1 >>> copier2.copyableTo(container) True """ 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 @adapter(IContainer) @implementer(IContainerItemRenamer) 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 """ 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) @adapter(IOrderedContainer) @implementer(IContainerItemRenamer) 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 """ 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 @adapter(IAnnotations) @implementer(IPrincipalClipboard) class PrincipalClipboard(object): """Principal clipboard Clipboard information consists of mappings of ``{'action':action, 'target':target}``. """ 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', ()) @implementer(INameChooser) class ExampleContainer(SampleContainer): # Sample container used for examples in doc stringss in this module 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__) >>> @implementer(ISublocations) ... class C(L): ... 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 = sorted(map(repr, seen)) >>> 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-4.0.0a1/src/zope/copypastemove/tests/0000775000000000000000000000000012357561405022123 5ustar rootrootzope.copypastemove-4.0.0a1/src/zope/copypastemove/tests/test_configure.py0000664000000000000000000000335212112560404025503 0ustar rootroot############################################################################## # # Copyright (c) 2011 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. # ############################################################################## import unittest import zope.copypastemove import zope.component import zope.configuration.xmlconfig class ZCMLTest(unittest.TestCase): def test_configure_zcml_should_be_loadable(self): try: zope.configuration.xmlconfig.XMLConfig( 'configure.zcml', zope.copypastemove)() except Exception as e: self.fail(e) def test_configure_should_register_n_components(self): gsm = zope.component.getGlobalSiteManager() u_count = len(list(gsm.registeredUtilities())) a_count = len(list(gsm.registeredAdapters())) s_count = len(list(gsm.registeredSubscriptionAdapters())) h_count = len(list(gsm.registeredHandlers())) zope.configuration.xmlconfig.XMLConfig( 'configure.zcml', zope.copypastemove)() self.assertEqual(u_count + 17, len(list(gsm.registeredUtilities()))) self.assertEqual(a_count + 5, len(list(gsm.registeredAdapters()))) self.assertEqual( s_count, len(list(gsm.registeredSubscriptionAdapters()))) self.assertEqual(h_count + 1, len(list(gsm.registeredHandlers()))) zope.copypastemove-4.0.0a1/src/zope/copypastemove/tests/test_objectmover.py0000664000000000000000000001664712112560404026054 0ustar rootroot############################################################################## # # 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 doctest import re import unittest 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.testing import renormalizing from zope.container import testing checker = renormalizing.RENormalizing([ # Python 3 unicode removed the "u". (re.compile("u('.*?')"), r"\1"), (re.compile('u(".*?")'), r"\1"), ]) 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, checker=checker), )) zope.copypastemove-4.0.0a1/src/zope/copypastemove/tests/test_objectcopier.py0000664000000000000000000001616112112560404026174 0ustar rootroot############################################################################## # # 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 doctest import re import unittest 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.testing import renormalizing from zope.container import testing checker = renormalizing.RENormalizing([ # Python 3 unicode removed the "u". (re.compile("u('.*?')"), r"\1"), (re.compile('u(".*?")'), r"\1"), ]) 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, checker=checker), )) zope.copypastemove-4.0.0a1/src/zope/copypastemove/tests/test_rename.py0000664000000000000000000001111212112560404024762 0ustar rootroot############################################################################## # # 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 doctest import re import unittest from zope.component import testing, eventtesting, provideAdapter, adapter 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 from zope.testing import renormalizing checker = renormalizing.RENormalizing([ # Python 3 unicode removed the "u". (re.compile("u('.*?')"), r"\1"), (re.compile('u(".*?")'), r"\1"), ]) class TestContainer(SampleContainer): pass @adapter(TestContainer) class ObstinateNameChooser(NameChooser): 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 adapter, 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 >>> import codecs >>> from zope.interface import implementer, Interface >>> from zope.container.interfaces import INameChooser >>> class IMyContainer(Interface): pass >>> @adapter(IMyContainer) ... @implementer(INameChooser) ... class MyNameChooser(object): ... def __init__(self, container): ... self.container = container ... def chooseName(self, name, obj): ... return codecs.getencoder('rot-13')(name)[0] >>> 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(): flags = \ doctest.NORMALIZE_WHITESPACE | \ doctest.ELLIPSIS | \ doctest.IGNORE_EXCEPTION_DETAIL return unittest.TestSuite(( unittest.makeSuite(RenamerTest), doctest.DocTestSuite('zope.copypastemove', setUp=setUp, tearDown=testing.tearDown, checker=checker, optionflags=flags), doctest.DocTestSuite(setUp=setUp, tearDown=testing.tearDown), )) zope.copypastemove-4.0.0a1/src/zope/copypastemove/tests/__init__.py0000664000000000000000000000001712112560404024215 0ustar rootroot# Import this. zope.copypastemove-4.0.0a1/src/zope/copypastemove/tests/test_metadata.py0000664000000000000000000000727212112560404025307 0ustar rootroot############################################################################## # # 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-4.0.0a1/src/zope/copypastemove/tests/test_clipboard.py0000664000000000000000000000666312112560404025471 0ustar rootroot############################################################################## # # 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-4.0.0a1/src/zope/copypastemove/interfaces.py0000664000000000000000000000561312112560404023446 0ustar rootroot############################################################################## # # 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, implementer 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 @implementer(IItemNotFoundError) class ItemNotFoundError(LookupError): pass zope.copypastemove-4.0.0a1/src/zope.copypastemove.egg-info/0000775000000000000000000000000012357561405022452 5ustar rootrootzope.copypastemove-4.0.0a1/src/zope.copypastemove.egg-info/top_level.txt0000664000000000000000000000000512112562040025160 0ustar rootrootzope zope.copypastemove-4.0.0a1/src/zope.copypastemove.egg-info/dependency_links.txt0000664000000000000000000000000112112562040026501 0ustar rootroot zope.copypastemove-4.0.0a1/src/zope.copypastemove.egg-info/SOURCES.txt0000664000000000000000000000156712112562040024330 0ustar rootrootCHANGES.txt COPYRIGHT.txt LICENSE.txt MANIFEST.in README.txt bootstrap.py buildout.cfg setup.py tox.ini 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_configure.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-4.0.0a1/src/zope.copypastemove.egg-info/namespace_packages.txt0000664000000000000000000000000512112562040026761 0ustar rootrootzope zope.copypastemove-4.0.0a1/src/zope.copypastemove.egg-info/requires.txt0000664000000000000000000000044712112562040025040 0ustar rootrootsetuptools 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.8 [zcml] zope.component[zcml] zope.configuration zope.security[zcml]zope.copypastemove-4.0.0a1/src/zope.copypastemove.egg-info/PKG-INFO0000664000000000000000000001124712112562040023535 0ustar rootrootMetadata-Version: 1.1 Name: zope.copypastemove Version: 4.0.0a1 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 ======= 4.0.0a1 (2013-02-24) -------------------- - Added support for Python 3.3. - Replaced deprecated ``zope.component.adapts`` usage with equivalent ``zope.component.adapter`` decorator. - Replaced deprecated ``zope.interface.implements`` usage with equivalent ``zope.interface.implementer`` decorator. - Dropped support for Python 2.4 and 2.5. - Include zcml dependencies in configure.zcml, require the necessary packages via a zcml extra, added tests for zcml. 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: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Zope3 zope.copypastemove-4.0.0a1/src/zope.copypastemove.egg-info/not-zip-safe0000664000000000000000000000000112112560404024663 0ustar rootroot zope.copypastemove-4.0.0a1/setup.cfg0000664000000000000000000000007312112562044016125 0ustar rootroot[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 zope.copypastemove-4.0.0a1/COPYRIGHT.txt0000664000000000000000000000004012112560404016405 0ustar rootrootZope Foundation and Contributorszope.copypastemove-4.0.0a1/MANIFEST.in0000664000000000000000000000017512112560404016043 0ustar rootrootinclude *.rst include *.txt include *.py include buildout.cfg include tox.ini recursive-include src * global-exclude *.pyc zope.copypastemove-4.0.0a1/PKG-INFO0000664000000000000000000001124712112562044015406 0ustar rootrootMetadata-Version: 1.1 Name: zope.copypastemove Version: 4.0.0a1 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 ======= 4.0.0a1 (2013-02-24) -------------------- - Added support for Python 3.3. - Replaced deprecated ``zope.component.adapts`` usage with equivalent ``zope.component.adapter`` decorator. - Replaced deprecated ``zope.interface.implements`` usage with equivalent ``zope.interface.implementer`` decorator. - Dropped support for Python 2.4 and 2.5. - Include zcml dependencies in configure.zcml, require the necessary packages via a zcml extra, added tests for zcml. 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: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Zope3 zope.copypastemove-4.0.0a1/LICENSE.txt0000664000000000000000000000402612112560404016127 0ustar rootrootZope 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-4.0.0a1/README.txt0000664000000000000000000000062512112560404016003 0ustar rootrootOverview --------- 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-4.0.0a1/setup.py0000664000000000000000000000744112112560404016022 0ustar rootroot############################################################################## # # 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. ############################################################################## from setuptools import setup, find_packages def alltests(): import os import sys import unittest # use the zope.testrunner machinery to find all the # test suites we've put under ourselves import zope.testrunner.find import zope.testrunner.options here = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src')) args = sys.argv[:] defaults = ["--test-path", here] options = zope.testrunner.options.get_options(args, defaults) suites = list(zope.testrunner.find.find_suites(options)) return unittest.TestSuite(suites) long_description = (open('README.txt').read() + '\n\n' + open('CHANGES.txt').read()) setup(name='zope.copypastemove', version='4.0.0a1', 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', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: Implementation :: CPython', 'Natural Language :: English', 'Operating System :: OS Independent', 'Topic :: Internet :: WWW/HTTP', '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', ], zcml=[ 'zope.component[zcml]', 'zope.configuration', 'zope.security[zcml]', ]), install_requires=['setuptools', 'zope.annotation', 'zope.component', 'zope.container', 'zope.copy', 'zope.event', 'zope.exceptions', 'zope.interface', 'zope.lifecycleevent', 'zope.location', ], tests_require = [ 'zope.dublincore', 'zope.principalannotation', 'zope.testing', 'zope.testrunner', 'zope.traversing', ], test_suite = '__main__.alltests', include_package_data = True, zip_safe = False, )