[Zope-CVS] SVN: book/trunk/keeperannotations/ Add code developed in
Annotations chapter.
Stephan Richter
srichter at cosmos.phy.tufts.edu
Mon Aug 16 15:37:11 EDT 2004
Log message for revision 27150:
Add code developed in Annotations chapter.
Changed:
A book/trunk/keeperannotations/
A book/trunk/keeperannotations/__init__.py
A book/trunk/keeperannotations/configure.zcml
A book/trunk/keeperannotations/ftests.py
A book/trunk/keeperannotations/interfaces.py
A book/trunk/keeperannotations/keeper.zcml
A book/trunk/keeperannotations/tests.py
-=-
Added: book/trunk/keeperannotations/__init__.py
===================================================================
--- book/trunk/keeperannotations/__init__.py 2004-08-16 19:24:35 UTC (rev 27149)
+++ book/trunk/keeperannotations/__init__.py 2004-08-16 19:37:11 UTC (rev 27150)
@@ -0,0 +1,138 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation 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.
+#
+##############################################################################
+"""Implementation of an Annotation Keeper Adapter
+
+$Id$
+"""
+from BTrees.OOBTree import OOBTree
+
+from zope.interface import implements
+from zope.proxy import removeAllProxies
+
+from zope.app import zapi
+from zope.app.annotation.interfaces import IAnnotations
+
+from interfaces import IKeeperAnnotatable, IAnnotationKeeper
+
+keeper_key = 'book.keeperannotation.KeeperAnnotations'
+
+tmp = {}
+
+class KeeperAnnotations(object):
+ """Store the annotations in a keeper.
+ >>> from zope.interface import directlyProvides
+ >>> from zope.app.dublincore.interfaces import IZopeDublinCore
+ >>> import datetime
+
+ Tell the File class that its instances implement IKeeperAnnotable
+
+ >>> from zope.app.file import File
+ >>> file = File()
+ >>> directlyProvides(file, IKeeperAnnotatable)
+ >>> dc = IZopeDublinCore(file)
+ >>> dc.created = dc.modified = datetime.datetime(2004, 01, 01, 12, 00)
+ >>> dc_data = tmp[file]['zope.app.dublincore.ZopeDublinCore']
+ >>> dc_data[u'Date.Created'][0]
+ u'2004-01-01T12:00:00'
+ >>> dc_data[u'Date.Modified'][0]
+ u'2004-01-01T12:00:00'
+
+ Let's make the RootFolder the annotation keeper
+
+ >>> from zope.app.folder.interfaces import IRootFolder
+ >>> from zope.app.folder import Folder
+ >>> root = Folder()
+ >>> directlyProvides(root, IAnnotationKeeper, IRootFolder)
+
+ Now we need to build up a simple tree
+
+ >>> root['folder1'] = Folder()
+ >>> root['folder1']['file'] = file
+ >>> file = root['folder1']['file']
+
+ Next we would like to store some DC data in the file
+
+ >>> dc = IZopeDublinCore(file)
+ >>> dc.title = u'File Title'
+ >>> dc.description = u'This is a file'
+
+ This is the moment; let's see where the annotation was stored.
+
+ >>> ann = root.__annotations__[keeper_key][file]
+ >>> dc_ann = ann['zope.app.dublincore.ZopeDublinCore']
+ >>> dc_ann[u'Title'][0]
+ u'File Title'
+ >>> dc_ann[u'Description'][0]
+ u'This is a file'
+ >>> dc_ann[u'Date.Created'][0]
+ u'2004-01-01T12:00:00'
+ >>> dc_ann[u'Date.Modified'][0]
+ u'2004-01-01T12:00:00'
+
+ Make sure the temporary entries have been removed
+
+ >>> tmp
+ {}
+ """
+ implements(IAnnotations)
+ __used_for__ = IKeeperAnnotatable
+
+ def __init__(self, obj):
+ self.obj = obj
+ self.obj_key = removeAllProxies(obj)
+ self.keeper_annotations = None
+
+ # Annotations might be set when object has no context
+ if not hasattr(obj, '__parent__') or obj.__parent__ is None:
+ self.keeper_annotations = tmp
+ return
+
+ for parent in zapi.getParents(obj):
+ if IAnnotationKeeper.providedBy(parent):
+ # We found the keeper, get the annotation that will store
+ # the data.
+ annotations = IAnnotations(parent)
+ if not annotations.has_key(keeper_key):
+ annotations[keeper_key] = OOBTree()
+ self.keeper_annotations = annotations[keeper_key]
+
+ if self.keeper_annotations == None:
+ raise ValueError, 'No annotation keeper found.'
+
+ # There are some temporary stored annotations; add them to the keeper
+ if tmp.has_key(obj):
+ self.keeper_annotations[self.obj_key] = tmp[obj]
+ del tmp[obj]
+
+ def __getitem__(self, key):
+ """See zope.app.annotation.interfaces.IAnnotations"""
+ annotations = self.keeper_annotations.get(self.obj_key, {})
+ return annotations[key]
+
+ def __setitem__(self, key, value):
+ """See zope.app.annotation.interfaces.IAnnotations"""
+ if not self.keeper_annotations.has_key(self.obj_key):
+ self.keeper_annotations[self.obj_key] = OOBTree()
+ self.keeper_annotations[self.obj_key][key] = value
+
+ def get(self, key, default=None):
+ """See zope.app.annotation.interfaces.IAnnotations"""
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+ def __delitem__(self, key):
+ """See zope.app.annotation.interfaces.IAnnotations"""
+ del self.keeper_annotations[self.obj_key][key]
Added: book/trunk/keeperannotations/configure.zcml
===================================================================
--- book/trunk/keeperannotations/configure.zcml 2004-08-16 19:24:35 UTC (rev 27149)
+++ book/trunk/keeperannotations/configure.zcml 2004-08-16 19:37:11 UTC (rev 27150)
@@ -0,0 +1,11 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="zope">
+
+ <adapter
+ for=".interfaces.IKeeperAnnotatable"
+ provides="zope.app.annotation.interfaces.IAnnotations"
+ factory=".KeeperAnnotations" />
+
+</configure>
Added: book/trunk/keeperannotations/ftests.py
===================================================================
--- book/trunk/keeperannotations/ftests.py 2004-08-16 19:24:35 UTC (rev 27149)
+++ book/trunk/keeperannotations/ftests.py 2004-08-16 19:37:11 UTC (rev 27150)
@@ -0,0 +1,74 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation 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.
+#
+##############################################################################
+"""Functional tests for KeeperAnnotations
+
+$Id$
+"""
+import time
+import unittest
+
+from zope.app.file import File
+from zope.app.tests.functional import BrowserTestCase
+
+from book.keeperannotations import keeper_key
+
+class KeeperFile(File):
+ pass
+
+
+class Test(BrowserTestCase):
+ """Funcional tests for Keeper Annotations.
+
+ This needs to have the configuration in 'keeper.zcml'
+ included in the setup of the functional tests.
+
+ Add the following directive to 'ftesting.zcml':
+
+ <include file="src/book/keeperannotations/keeper.zcml" />
+
+ """
+
+ def test_DC_Annotations(self):
+ # Create file
+ response = self.publish(
+ "/+/action.html?type_name=book.keeperannotations.KeeperFile",
+ basic='mgr:mgrpw')
+
+ self.assertEqual(response.getStatus(), 302)
+ self.assertEqual(response.getHeader('Location'),
+ 'http://localhost/@@contents.html')
+
+ # Update the file's title
+ self.publish("/@@contents.html",
+ basic='mgr:mgrpw',
+ form={'retitle_id' : 'KeeperFile',
+ 'new_value' : u'File Title'})
+
+ root = self.getRootFolder()
+ file = root['KeeperFile']
+ ann = root.__annotations__[keeper_key][file]
+ dc_ann = ann['zope.app.dublincore.ZopeDublinCore']
+ self.assert_(dc_ann[u'Date.Created'][0] > u'2004-01-01T12:00:00')
+ self.assert_(dc_ann[u'Date.Created'][0] == dc_ann[u'Date.Modified'][0])
+ self.assertEqual(dc_ann[u'Title'][0], u'File Title')
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(Test),
+ ))
+
+if __name__=='__main__':
+ unittest.main(defaultTest='test_suite')
+
Added: book/trunk/keeperannotations/interfaces.py
===================================================================
--- book/trunk/keeperannotations/interfaces.py 2004-08-16 19:24:35 UTC (rev 27149)
+++ book/trunk/keeperannotations/interfaces.py 2004-08-16 19:37:11 UTC (rev 27150)
@@ -0,0 +1,38 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation 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.
+#
+##############################################################################
+"""Interfaces for an Annotation Keeper
+
+$Id$
+"""
+from zope.interface import Interface
+from zope.app.annotation.interfaces import IAnnotatable
+
+class IAnnotationKeeper(Interface):
+ """Marker indicating that an object is willing to store other object's
+ annotations in its own annotations.
+
+ This interface makes only sense, if the object that implements this
+ interface also implements 'IAnnotatable' or any sub-class.
+ """
+
+class IKeeperAnnotatable(IAnnotatable):
+ """Marker indicating that an object will store its annotations in an
+ object implementing IAnnotationKeeper.
+
+ This requires the object that provides this interface to also implement
+ ILocation.
+
+ This interface does not specify how the keeper may be found. This is up
+ to the adapter that uses this interface to provide 'IAnnotations'.
+ """
Added: book/trunk/keeperannotations/keeper.zcml
===================================================================
--- book/trunk/keeperannotations/keeper.zcml 2004-08-16 19:24:35 UTC (rev 27149)
+++ book/trunk/keeperannotations/keeper.zcml 2004-08-16 19:37:11 UTC (rev 27150)
@@ -0,0 +1,48 @@
+<configure
+ package="book.keeperannotations"
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="zope">
+
+ <content class="zope.app.folder.Folder">
+ <implements
+ interface=".interfaces.IAnnotationKeeper"
+ />
+ </content>
+
+ <content class=".ftests.KeeperFile">
+ <factory
+ id="book.keeperannotations.KeeperFile"
+ title="Keeper File"
+ description="A Keeper File"
+ />
+ <implements
+ interface=".interfaces.IKeeperAnnotatable"
+ />
+ <require
+ permission="zope.View"
+ interface="zope.app.filerepresentation.interfaces.IReadFile"
+ />
+ <require
+ permission="zope.ManageContent"
+ interface="zope.app.filerepresentation.interfaces.IWriteFile"
+ set_schema="zope.app.filerepresentation.interfaces.IReadFile"
+ />
+ </content>
+
+ <browser:addMenuItem
+ class=".ftests.KeeperFile"
+ title="Keeper File"
+ permission="zope.ManageContent"
+ view="KeeperFile"
+ />
+
+ <browser:addform
+ schema="zope.app.file.interfaces.IFile"
+ label="Add a Keeper File"
+ content_factory=".ftests.KeeperFile"
+ name="AddKeeperFile"
+ permission="zope.ManageContent"
+ />
+
+</configure>
Added: book/trunk/keeperannotations/tests.py
===================================================================
--- book/trunk/keeperannotations/tests.py 2004-08-16 19:24:35 UTC (rev 27149)
+++ book/trunk/keeperannotations/tests.py 2004-08-16 19:37:11 UTC (rev 27150)
@@ -0,0 +1,57 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation 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.
+#
+##############################################################################
+"""Unit tests for KeeperAnnotations
+
+$Id$
+"""
+import unittest
+
+from zope.interface import classImplements
+from zope.testing.doctestunit import DocTestSuite
+
+from zope.app.annotation.attribute import AttributeAnnotations
+from zope.app.folder import Folder
+from zope.app.dublincore.annotatableadapter import ZDCAnnotatableAdapter
+from zope.app.annotation.interfaces import \
+ IAnnotations, IAnnotatable, IAttributeAnnotatable
+from zope.app.dublincore.interfaces import IWriteZopeDublinCore
+from zope.app.location.interfaces import ILocation
+from zope.app.traversing.interfaces import IPhysicallyLocatable
+from zope.app.location.traversing import LocationPhysicallyLocatable
+from zope.app.tests import ztapi
+from zope.app.tests.placelesssetup import setUp, tearDown
+
+from book.keeperannotations.interfaces import IKeeperAnnotatable
+from book.keeperannotations import KeeperAnnotations
+
+def customSetUp():
+ setUp()
+ classImplements(Folder, IAttributeAnnotatable)
+ ztapi.provideAdapter(IKeeperAnnotatable, IAnnotations,
+ KeeperAnnotations)
+ ztapi.provideAdapter(ILocation, IPhysicallyLocatable,
+ LocationPhysicallyLocatable)
+ ztapi.provideAdapter(IAnnotatable, IWriteZopeDublinCore,
+ ZDCAnnotatableAdapter)
+ ztapi.provideAdapter(IAttributeAnnotatable, IAnnotations,
+ AttributeAnnotations)
+
+def test_suite():
+ return unittest.TestSuite((
+ DocTestSuite('book.keeperannotations',
+ setUp=customSetUp, tearDown=tearDown),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
More information about the Zope-CVS
mailing list