[Checkins] SVN: zope.copy/trunk/ Get doctest snippets testable.
Tres Seaver
cvs-admin at zope.org
Wed Jun 13 15:23:34 UTC 2012
Log message for revision 126847:
Get doctest snippets testable.
Changed:
_U zope.copy/trunk/
U zope.copy/trunk/docs/narr.rst
A zope.copy/trunk/src/zope/copy/examples.py
-=-
Modified: zope.copy/trunk/docs/narr.rst
===================================================================
--- zope.copy/trunk/docs/narr.rst 2012-06-13 15:23:27 UTC (rev 126846)
+++ zope.copy/trunk/docs/narr.rst 2012-06-13 15:23:31 UTC (rev 126847)
@@ -50,35 +50,31 @@
So, here is a simple object that stores a boolean on a special object.
-.. doctest::
+.. literalinclude:: ../src/zope/copy/examples.py
+ :pyobject: Demo
+ :prepend: # zope.copy.examples.Demo
- >>> class Demo(object):
- ... _frozen = None
- ... def isFrozen(self):
- ... return self._frozen is not None
- ... def freeze(self):
- ... self._frozen = Data()
- ...
- >>> class Data(object):
- ... pass
- ...
+.. literalinclude:: ../src/zope/copy/examples.py
+ :pyobject: Data
+ :prepend: # zope.copy.examples.Data
Here's what happens if we copy one of these objects without a copy hook.
.. doctest::
- >>> original = Demo()
- >>> original.isFrozen()
- False
- >>> original.freeze()
- >>> original.isFrozen()
- True
- >>> import zope.copy
- >>> copy = zope.copy.copy(original)
- >>> copy is original
- False
- >>> copy.isFrozen()
- True
+ >>> from zope.copy.examples import Demo, Data
+ >>> original = Demo()
+ >>> original.isFrozen()
+ False
+ >>> original.freeze()
+ >>> original.isFrozen()
+ True
+ >>> import zope.copy
+ >>> copy = zope.copy.copy(original)
+ >>> copy is original
+ False
+ >>> copy.isFrozen()
+ True
Now let's make a super-simple copy hook that always returns None, no
matter what the top-level object being copied is. We'll register it and
@@ -86,23 +82,23 @@
.. doctest::
- >>> import zope.component
- >>> import zope.interface
- >>> import zope.copy.interfaces
- >>> def _factory(obj, register):
- ... return None
- >>> @zope.component.adapter(Data)
- ... @zope.interface.implementer(zope.copy.interfaces.ICopyHook)
- ... def data_copyfactory(obj):
- ... return _factory
- ...
+ >>> import zope.component
+ >>> import zope.interface
+ >>> import zope.copy.interfaces
+ >>> def _factory(obj, register):
+ ... return None
+ >>> @zope.component.adapter(Data)
+ ... @zope.interface.implementer(zope.copy.interfaces.ICopyHook)
+ ... def data_copyfactory(obj):
+ ... return _factory
+ ...
- >>> zope.component.provideAdapter(data_copyfactory)
- >>> copy2 = zope.copy.copy(original)
- >>> copy2 is original
- False
- >>> copy2.isFrozen()
- False
+ >>> zope.component.provideAdapter(data_copyfactory)
+ >>> copy2 = zope.copy.copy(original)
+ >>> copy2 is original
+ False
+ >>> copy2.isFrozen()
+ False
Much better.
@@ -118,47 +114,44 @@
Imagine an object with a subobject that is "located" (i.e., zope.location) on
the parent and should be replaced whenever the main object is copied.
+.. literalinclude:: ../src/zope/copy/examples.py
+ :pyobject: Subobject
+ :prepend: # zope.copy.examples.Subobject
+
.. doctest::
- >>> import zope.location.location
- >>> class Subobject(zope.location.location.Location):
- ... def __init__(self):
- ... self.counter = 0
- ... def __call__(self):
- ... res = self.counter
- ... self.counter += 1
- ... return res
- ...
- >>> o = zope.location.location.Location()
- >>> s = Subobject()
- >>> o.subobject = s
- >>> zope.location.location.locate(s, o, 'subobject')
- >>> s.__parent__ is o
- True
- >>> o.subobject()
- 0
- >>> o.subobject()
- 1
- >>> o.subobject()
- 2
+ >>> import zope.location.location
+ >>> from zope.copy.examples import Subobject
+ >>> o = zope.location.location.Location()
+ >>> s = Subobject()
+ >>> o.subobject = s
+ >>> zope.location.location.locate(s, o, 'subobject')
+ >>> s.__parent__ is o
+ True
+ >>> o.subobject()
+ 0
+ >>> o.subobject()
+ 1
+ >>> o.subobject()
+ 2
Without an ICopyHook, this will simply duplicate the subobject, with correct
new pointers.
.. doctest::
- >>> c = zope.copy.copy(o)
- >>> c.subobject.__parent__ is c
- True
+ >>> c = zope.copy.copy(o)
+ >>> c.subobject.__parent__ is c
+ True
Note that the subobject has also copied state.
.. doctest::
- >>> c.subobject()
- 3
- >>> o.subobject()
- 3
+ >>> c.subobject()
+ 3
+ >>> o.subobject()
+ 3
Our goal will be to make the counters restart when they are copied. We'll do
that with a copy hook.
@@ -172,34 +165,34 @@
.. doctest::
- >>> import zope.component
- >>> import zope.interface
- >>> import zope.copy.interfaces
- >>> @zope.component.adapter(Subobject)
- ... @zope.interface.implementer(zope.copy.interfaces.ICopyHook)
- ... def subobject_copyfactory(original):
- ... def factory(obj, register):
- ... obj = Subobject()
- ... def reparent(translate):
- ... obj.__parent__ = translate(original.__parent__)
- ... register(reparent)
- ... return obj
- ... return factory
- ...
- >>> zope.component.provideAdapter(subobject_copyfactory)
+ >>> import zope.component
+ >>> import zope.interface
+ >>> import zope.copy.interfaces
+ >>> @zope.component.adapter(Subobject)
+ ... @zope.interface.implementer(zope.copy.interfaces.ICopyHook)
+ ... def subobject_copyfactory(original):
+ ... def factory(obj, register):
+ ... obj = Subobject()
+ ... def reparent(translate):
+ ... obj.__parent__ = translate(original.__parent__)
+ ... register(reparent)
+ ... return obj
+ ... return factory
+ ...
+ >>> zope.component.provideAdapter(subobject_copyfactory)
Now when we copy, the new subobject will have the correct, revised __parent__,
but will be otherwise reset (here, just the counter)
.. doctest::
- >>> c = zope.copy.copy(o)
- >>> c.subobject.__parent__ is c
- True
- >>> c.subobject()
- 0
- >>> o.subobject()
- 4
+ >>> c = zope.copy.copy(o)
+ >>> c.subobject.__parent__ is c
+ True
+ >>> c.subobject()
+ 0
+ >>> o.subobject()
+ 4
Resuming recursive copy
-----------------------
@@ -213,23 +206,23 @@
.. doctest::
- >>> root = zope.location.location.Location()
+ >>> root = zope.location.location.Location()
- >>> content = zope.location.location.Location()
- >>> zope.location.location.locate(content, root, 'content')
+ >>> content = zope.location.location.Location()
+ >>> zope.location.location.locate(content, root, 'content')
- >>> image = zope.location.location.Location()
- >>> zope.location.location.locate(image, root, 'image.jpg')
+ >>> image = zope.location.location.Location()
+ >>> zope.location.location.locate(image, root, 'image.jpg')
- >>> content.cover = image
+ >>> content.cover = image
Without any hooks, the image object will be cloned as well:
.. doctest::
- >>> new = zope.copy.copy(content)
- >>> new.cover is image
- False
+ >>> new = zope.copy.copy(content)
+ >>> new.cover is image
+ False
That's not what we'd expect though, so, let's provide a copy hook
to deal with that. The copy hook for this case is provided by zope.location
@@ -238,16 +231,16 @@
.. doctest::
- >>> @zope.component.adapter(zope.location.interfaces.ILocation)
- ... @zope.interface.implementer(zope.copy.interfaces.ICopyHook)
- ... def location_copyfactory(obj):
- ... def factory(location, register):
- ... if not zope.location.location.inside(obj, location):
- ... return obj
- ... raise zope.copy.interfaces.ResumeCopy
- ... return factory
- ...
- >>> zope.component.provideAdapter(location_copyfactory)
+ >>> @zope.component.adapter(zope.location.interfaces.ILocation)
+ ... @zope.interface.implementer(zope.copy.interfaces.ICopyHook)
+ ... def location_copyfactory(obj):
+ ... def factory(location, register):
+ ... if not zope.location.location.inside(obj, location):
+ ... return obj
+ ... raise zope.copy.interfaces.ResumeCopy
+ ... return factory
+ ...
+ >>> zope.component.provideAdapter(location_copyfactory)
This hook returns objects as they are if they are not located inside
object that's being copied, or raises ResumeCopy to signal that the
@@ -255,9 +248,9 @@
.. doctest::
- >>> new = zope.copy.copy(content)
- >>> new.cover is image
- True
+ >>> new = zope.copy.copy(content)
+ >>> new.cover is image
+ True
Much better :-)
@@ -273,10 +266,10 @@
.. doctest::
- >>> root = zope.location.location.Location()
- >>> folder = zope.location.location.Location()
- >>> folder.__name__ = 'files'
- >>> folder.__parent__ = root
+ >>> root = zope.location.location.Location()
+ >>> folder = zope.location.location.Location()
+ >>> folder.__name__ = 'files'
+ >>> folder.__parent__ = root
The :func:`clone` function will leave those attributes as is. Note that the
referenced __parent__ won't be cloned, as we registered a hook for locations
@@ -284,11 +277,11 @@
.. doctest::
- >>> folder_clone = zope.copy.clone(folder)
- >>> folder_clone.__parent__ is root
- True
- >>> folder_clone.__name__ == 'files'
- True
+ >>> folder_clone = zope.copy.clone(folder)
+ >>> folder_clone.__parent__ is root
+ True
+ >>> folder_clone.__name__ == 'files'
+ True
However, the :func:`copy` function will reset those attributes to None, as
we will probably want to place our object into another container with
@@ -296,11 +289,11 @@
.. doctest::
- >>> folder_clone = zope.copy.copy(folder)
- >>> folder_clone.__parent__ is None
- True
- >>> folder_clone.__name__ is None
- True
+ >>> folder_clone = zope.copy.copy(folder)
+ >>> folder_clone.__parent__ is None
+ True
+ >>> folder_clone.__name__ is None
+ True
Notice, that if your object doesn't have __parent__ and __name__
attributes at all, or these attributes could'nt be got or set because of
@@ -310,53 +303,46 @@
It won't set them if original object doesn't have them:
+.. literalinclude:: ../src/zope/copy/examples.py
+ :pyobject: Something
+ :prepend: # zope.copy.examples.Something
+
.. doctest::
- >>> class Something(object):
- ... pass
+ >>> from zope.copy.examples import Something
+ >>> s = Something()
+ >>> s_copy = zope.copy.copy(s)
+ >>> s_copy.__parent__
+ Traceback (most recent call last):
+ ...
+ AttributeError: ...
+ >>> s_copy.__name__
+ Traceback (most recent call last):
+ ...
+ AttributeError: ...
- >>> s = Something()
- >>> s_copy = zope.copy.copy(s)
- >>> s_copy.__parent__
- Traceback (most recent call last):
- ...
- AttributeError: ...
- >>> s_copy.__name__
- Traceback (most recent call last):
- ...
- AttributeError: ...
-
And it won't fail if original object has them but doesn't allow to set
them.
-.. doctest::
+.. literalinclude:: ../src/zope/copy/examples.py
+ :pyobject: Other
+ :prepend: # zope.copy.examples.Other
- >>> root = object()
- >>> class Something(object):
- ...
- ... @apply
- ... def __name__():
- ... def fget(self):
- ... return 'something'
- ... def fset(self, value):
- ... raise AttributeError
- ... return property(fget, fset)
- ...
- ... @apply
- ... def __parent__():
- ... def fget(self):
- ... return root
- ... def fset(self, value):
- ... raise AttributeError
- ... return property(fget, fset)
+.. literalinclude:: ../src/zope/copy/examples.py
+ :pyobject: root
+ :prepend: # zope.copy.examples.root
- >>> s = Something()
- >>> s_copy = zope.copy.copy(s)
- >>> s_copy.__parent__ is root
- True
- >>> s_copy.__name__ == 'something'
- True
+.. doctest::
+ >>> from zope.copy.examples import Other
+ >>> from zope.copy.examples import root
+ >>> s = Other()
+ >>> s_copy = zope.copy.copy(s)
+ >>> s_copy.__parent__ is root
+ True
+ >>> s_copy.__name__ == 'something'
+ True
+
:class:`~zope.location.pickling.LocationCopyHook`
-------------------------------------------------
@@ -375,30 +361,32 @@
.. doctest::
- >>> from zope.location.location import Location, locate
- >>> root = Location()
- >>> page = Location()
- >>> locate(page, root, 'page')
- >>> image = Location()
- >>> locate(page, root, 'image')
- >>> page.thumbnail = image
+ >>> from zope.component.globalregistry import base
+ >>> base.__init__('base') # blow away previous registrations
+ >>> from zope.location.location import Location, locate
+ >>> root = Location()
+ >>> page = Location()
+ >>> locate(page, root, 'page')
+ >>> image = Location()
+ >>> locate(page, root, 'image')
+ >>> page.thumbnail = image
- >>> from zope.copy import copy
- >>> page_copy = copy(page)
- >>> page_copy.thumbnail is image
- False
+ >>> from zope.copy import copy
+ >>> page_copy = copy(page)
+ >>> page_copy.thumbnail is image
+ False
But if we will provide a hook, the attribute will point to the
original object as we might want.
.. doctest::
- >>> from zope.component import provideAdapter
- >>> from zope.location.pickling import LocationCopyHook
- >>> from zope.location.interfaces import ILocation
- >>> provideAdapter(LocationCopyHook, (ILocation,))
+ >>> from zope.component import provideAdapter
+ >>> from zope.location.pickling import LocationCopyHook
+ >>> from zope.location.interfaces import ILocation
+ >>> provideAdapter(LocationCopyHook, (ILocation,))
- >>> from zope.copy import copy
- >>> page_copy = copy(page)
- >>> page_copy.thumbnail is image
- True
+ >>> from zope.copy import copy
+ >>> page_copy = copy(page)
+ >>> page_copy.thumbnail is image
+ True
Added: zope.copy/trunk/src/zope/copy/examples.py
===================================================================
--- zope.copy/trunk/src/zope/copy/examples.py (rev 0)
+++ zope.copy/trunk/src/zope/copy/examples.py 2012-06-13 15:23:31 UTC (rev 126847)
@@ -0,0 +1,65 @@
+##############################################################################
+#
+# Copyright (c) 2012 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.
+#
+##############################################################################
+""" Make example classes available at module scope.
+"""
+import zope.location.location
+
+class Demo(object):
+
+ _frozen = None
+
+ def isFrozen(self):
+ return self._frozen is not None
+
+ def freeze(self):
+ self._frozen = Data()
+
+
+class Data(object):
+ pass
+
+
+class Subobject(zope.location.location.Location):
+
+ def __init__(self):
+ self.counter = 0
+
+ def __call__(self):
+ res = self.counter
+ self.counter += 1
+ return res
+
+
+class Something(object):
+ pass
+
+
+root = object()
+
+
+class Other(object):
+ @apply
+ def __name__():
+ def fget(self):
+ return 'something'
+ def fset(self, value):
+ raise AttributeError
+ return property(fget, fset)
+ @apply
+ def __parent__():
+ def fget(self):
+ return root
+ def fset(self, value):
+ raise AttributeError
+ return property(fget, fset)
More information about the checkins
mailing list