[Zope3-checkins] SVN: Zope3/trunk/ Convenience factory to register
annotations. Also modified tests a bit
Martijn Faassen
faassen at infrae.com
Thu Mar 16 14:06:21 EST 2006
Log message for revision 66061:
Convenience factory to register annotations. Also modified tests a bit
and added README.txt doctest.
Changed:
U Zope3/trunk/doc/CHANGES.txt
A Zope3/trunk/src/zope/app/annotation/README.txt
U Zope3/trunk/src/zope/app/annotation/__init__.py
A Zope3/trunk/src/zope/app/annotation/_factory.py
U Zope3/trunk/src/zope/app/annotation/tests/annotations.py
U Zope3/trunk/src/zope/app/annotation/tests/test_attributeannotations.py
-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt 2006-03-16 17:20:08 UTC (rev 66060)
+++ Zope3/trunk/doc/CHANGES.txt 2006-03-16 19:06:20 UTC (rev 66061)
@@ -33,6 +33,10 @@
"pkg_resources" is available. This will enable distribution of
"zope.*" packages as individual eggs.
+ - A new zope.app.annotation.factory helper function that makes
+ it easier to create annotations. Also added a README in
+ zope.app.annotation which explains how to use it.
+
Restructuring
- Removed 'Adding.renderAddButton' method which had been
Added: Zope3/trunk/src/zope/app/annotation/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/annotation/README.txt 2006-03-16 17:20:08 UTC (rev 66060)
+++ Zope3/trunk/src/zope/app/annotation/README.txt 2006-03-16 19:06:20 UTC (rev 66061)
@@ -0,0 +1,94 @@
+Annotations
+===========
+
+There is more to document about annotations, but we'll just sketch out
+a scenario on how to use the annotation factory for now. This is one
+of the easiest ways to use annotations -- basically you can see them
+as persistent, writeable adapters.
+
+First, let's make a persistent object we can create annotations for:
+
+ >>> from zope import interface
+ >>> class IFoo(interface.Interface):
+ ... pass
+ >>> from zope.app.annotation.interfaces import IAttributeAnnotatable
+ >>> from persistent import Persistent
+ >>> class Foo(Persistent):
+ ... interface.implements(IFoo, IAttributeAnnotatable)
+
+We directly say that Foo implements IAttributeAnnotatable here. In
+practice this is often done in ZCML, using the `implements`
+subdirective of the `content` or `class` directive.
+
+Now let's create an annotation for this:
+
+ >>> class IBar(interface.Interface):
+ ... a = interface.Attribute('A')
+ ... b = interface.Attribute('B')
+ >>> from zope import component
+ >>> class Bar(Persistent):
+ ... interface.implements(IBar)
+ ... component.adapts(IFoo)
+ ... def __init__(self):
+ ... self.a = 1
+ ... self.b = 2
+
+Note that the annotation implementation does not expect any arguments
+to its `__init__`. Otherwise it's basically an adapter.
+
+Now, we'll register the annotation as an adapter. Do do this we use
+the `factory` function provided by `zope.app.annotation`:
+
+ >>> from zope.app.annotation import factory
+ >>> component.provideAdapter(factory(Bar))
+
+Note that we do not need to specify what the adapter provides or what
+it adapts - we already do this on the annotation class itself.
+
+Now we let's make an instance of `Foo`, and make an annotation for it.
+
+ >>> foo = Foo()
+ >>> bar = IBar(foo)
+ >>> bar.a
+ 1
+ >>> bar.b
+ 2
+
+We'll change `a` and get the annotation again. Our change is still
+there:
+
+ >>> bar.a = 3
+ >>> IBar(foo).a
+ 3
+
+Of course it's still different for another instance of `Foo`:
+
+ >>> foo2 = Foo()
+ >>> IBar(foo2).a
+ 1
+
+What if our annotation does not provide what it adapts with
+`component.adapts`? It will complain:
+
+ >>> class IQux(interface.Interface):
+ ... pass
+ >>> class Qux(Persistent):
+ ... interface.implements(IQux)
+ >>> component.provideAdapter(factory(Qux)) # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ TypeError: Missing 'zope.component.adapts' on annotation
+
+It's possible to provide an annotation with an explicit key. (If the
+key is not supplied, the key is deduced from the anotation's dotted
+name, provided it is a class.)
+
+ >>> class IHoi(interface.Interface):
+ ... pass
+ >>> class Hoi(Persistent):
+ ... interface.implements(IHoi)
+ ... component.adapts(IFoo)
+ >>> component.provideAdapter(factory(Hoi, 'my.unique.key'))
+ >>> isinstance(IHoi(foo), Hoi)
+ True
+
Modified: Zope3/trunk/src/zope/app/annotation/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/annotation/__init__.py 2006-03-16 17:20:08 UTC (rev 66060)
+++ Zope3/trunk/src/zope/app/annotation/__init__.py 2006-03-16 19:06:20 UTC (rev 66061)
@@ -18,3 +18,4 @@
from zope.app.annotation.interfaces import IAttributeAnnotatable
from zope.app.annotation.interfaces import IAnnotations
+from zope.app.annotation._factory import factory
Added: Zope3/trunk/src/zope/app/annotation/_factory.py
===================================================================
--- Zope3/trunk/src/zope/app/annotation/_factory.py 2006-03-16 17:20:08 UTC (rev 66060)
+++ Zope3/trunk/src/zope/app/annotation/_factory.py 2006-03-16 19:06:20 UTC (rev 66061)
@@ -0,0 +1,30 @@
+import zope.component
+import zope.interface
+from zope.app.annotation.interfaces import IAnnotations
+import zope.app.container.contained
+
+def factory(factory, key=None):
+ """Adapter factory to help create annotations easily.
+ """
+ # if no key is provided,
+ # we'll determine the unique key based on the factory's dotted name
+ if key is None:
+ key = factory.__module__ + '.' + factory.__name__
+
+ adapts = zope.component.adaptedBy(factory)
+ if adapts is None:
+ raise TypeError("Missing 'zope.component.adapts' on annotation")
+
+ @zope.component.adapter(list(adapts)[0])
+ @zope.interface.implementer(list(zope.component.implementedBy(factory))[0])
+ def getAnnotation(context):
+ annotations = IAnnotations(context)
+ try:
+ return annotations[key]
+ except KeyError:
+ result = factory()
+ annotations[key] = result
+ zope.app.container.contained.contained(
+ result, context, key)
+ return result
+ return getAnnotation
Modified: Zope3/trunk/src/zope/app/annotation/tests/annotations.py
===================================================================
--- Zope3/trunk/src/zope/app/annotation/tests/annotations.py 2006-03-16 17:20:08 UTC (rev 66060)
+++ Zope3/trunk/src/zope/app/annotation/tests/annotations.py 2006-03-16 19:06:20 UTC (rev 66061)
@@ -22,10 +22,10 @@
from zope.interface.verify import verifyObject
from zope.app.annotation.interfaces import IAnnotations
-class IAnnotationsTest(unittest.TestCase):
+class AnnotationsTest(unittest.TestCase):
"""Test the IAnnotations interface.
- The test case class expects the 'IAnnotations' to be in
+ The test case class expects the 'IAnnotations' implementer to be in
'self.annotations'.
"""
Modified: Zope3/trunk/src/zope/app/annotation/tests/test_attributeannotations.py
===================================================================
--- Zope3/trunk/src/zope/app/annotation/tests/test_attributeannotations.py 2006-03-16 17:20:08 UTC (rev 66060)
+++ Zope3/trunk/src/zope/app/annotation/tests/test_attributeannotations.py 2006-03-16 19:06:20 UTC (rev 66061)
@@ -11,29 +11,45 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Tests the 'AttributeAnnotations' adapter.
+"""Tests the 'AttributeAnnotations' adapter. Also test the annotation
+factory.
$Id$
"""
-from unittest import main, makeSuite
-from zope.testing.cleanup import CleanUp # Base class w registry cleanup
-from zope.app.annotation.tests.annotations import IAnnotationsTest
+import unittest, doctest
+from zope.testing import cleanup
+from zope.app.annotation.tests.annotations import AnnotationsTest
from zope.app.annotation.attribute import AttributeAnnotations
from zope.app.annotation.interfaces import IAttributeAnnotatable
from zope.interface import implements
+from zope import component
class Dummy(object):
implements(IAttributeAnnotatable)
-class AttributeAnnotationsTest(IAnnotationsTest, CleanUp):
+class AttributeAnnotationsTest(AnnotationsTest, cleanup.CleanUp):
def setUp(self):
self.annotations = AttributeAnnotations(Dummy())
super(AttributeAnnotationsTest, self).setUp()
+def setUp(test=None):
+ cleanup.setUp()
+ component.provideAdapter(AttributeAnnotations)
+
+def tearDown(test=None):
+ cleanup.tearDown()
+
def test_suite():
- return makeSuite(AttributeAnnotationsTest)
+ return unittest.TestSuite((
+ unittest.makeSuite(AttributeAnnotationsTest),
+ doctest.DocFileSuite('../README.txt', setUp=setUp, tearDown=tearDown)
+ ))
+ #return makeSuite(AttributeAnnotationsTest)
+ # doctest.DocFileSuite('README.txt',
+ # setUp=setUp, tearDown=tearDown),
+
if __name__=='__main__':
- main(defaultTest='test_suite')
+ unittest.main(defaultTest='test_suite')
More information about the Zope3-Checkins
mailing list