[Zope3-checkins] CVS: Zope3/src/zope/app/broken - tests.py:1.1 broken.py:1.3 configure.zcml:1.3

Jim Fulton jim at zope.com
Thu Mar 4 17:41:47 EST 2004


Update of /cvs-repository/Zope3/src/zope/app/broken
In directory cvs.zope.org:/tmp/cvs-serv3904/src/zope/app/broken

Modified Files:
	broken.py configure.zcml 
Added Files:
	tests.py 
Log Message:
Adden annotation support for broken objects. Also added some 
logic to set a checker on broken classes. This is necessary
because broken classes are generated when needed.


=== Added File Zope3/src/zope/app/broken/tests.py ===
##############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""Broken-object tests

$Id: tests.py,v 1.1 2004/03/04 22:41:47 jim Exp $
"""
import unittest
from zope.testing.doctestunit import DocTestSuite

def test_annotations():
    """Broken objects may have attribute annotations

    If they do, we can access them::

      >>> from zope.app.broken.broken import Broken
      >>> b = Broken()
      >>> b.__setstate__({'__annotations__': {'foo.bar': 42}})
      >>> b['foo.bar']
      42
      >>> b.get('foo.bar')
      42

      Missing keys are handled as expected:

      >>> b['foo.baz']
      Traceback (most recent call last):
      ...
      KeyError: 'foo.baz'

      >>> b.get('foo.baz')

      It is an error to modify annotations:

      >>> b['foo.baz'] = []
      Traceback (most recent call last):
      ...
      BrokenModified: Can't modify broken objects

      >>> del b['foo.bar']
      Traceback (most recent call last):
      ...
      BrokenModified: Can't modify broken objects

    If there are no annotation data, then, obviously, there are no annotations:

      >>> b = Broken()
      >>> b['foo.bar']
      Traceback (most recent call last):
      ...
      KeyError: 'foo.bar'

      >>> b.get('foo.bar')

      >>> b['foo.bar'] = []
      Traceback (most recent call last):
      ...
      BrokenModified: Can't modify broken objects

      >>> del b['foo.bar']
      Traceback (most recent call last):
      ...
      BrokenModified: Can't modify broken objects
    

    Cleanup:

      >>> import ZODB.broken
      >>> ZODB.broken.broken_cache.clear()

    """

def test_suite():
    return unittest.TestSuite((
        DocTestSuite(),
        DocTestSuite('zope.app.broken.broken'),
        ))

if __name__ == '__main__': unittest.main()


=== Zope3/src/zope/app/broken/broken.py 1.2 => 1.3 ===
--- Zope3/src/zope/app/broken/broken.py:1.2	Tue Mar  2 12:51:49 2004
+++ Zope3/src/zope/app/broken/broken.py	Thu Mar  4 17:41:47 2004
@@ -21,13 +21,21 @@
 import zope.interface
 import zope.app.location.interfaces
 import zope.app.event.function
+import zope.security.checker
+
+
+from zope.app.interfaces.annotation import IAnnotations
 
 class IBroken(zope.interface.Interface):
     """Marker interface for broken objects
     """
 
 class Broken(ZODB.broken.Broken):
-    zope.interface.implements(IBroken, zope.app.location.interfaces.ILocation)
+    zope.interface.implements(
+        IBroken,
+        zope.app.location.interfaces.ILocation,
+        IAnnotations,
+        )
 
     def __parent__(self):
         return self.__Broken_state__.get('__parent__')
@@ -39,14 +47,86 @@
     
     __name__ = property(__name__)
 
+    def __getAnnotations(self):
+        get = getattr(self.__Broken_state__, 'get', None)
+        if get is not None:
+            return get('__annotations__')
+
+    def __getitem__(self, key):
+        annotations = self.__getAnnotations()
+        if annotations:
+            return annotations[key]
+        raise KeyError, key
+
+    def __setitem__(self, key, value):
+        raise ZODB.broken.BrokenModified("Can't modify broken objects")
+
+    def __delitem__(self, key):
+        raise ZODB.broken.BrokenModified("Can't modify broken objects")
+
+    def get(self, key, default=None):
+        annotations = self.__getAnnotations()
+        if annotations is None:
+            return default
+        return annotations.get(key, default)
+
 def installBroken(event):
+    """Install a class factory that handled broken objects
+
+    This method installs a custom class factory when it gets a
+    database-opened event::
+
+      >>> import ZODB.tests.util
+      >>> from zope.app.process.event import DatabaseOpened
+      >>> db = ZODB.tests.util.DB()
+      >>> installBroken(DatabaseOpened(db))
+    
+    If someone tries to load an object for which there is no class,
+    then they will get a Broken object. We can simulate that by
+    calling the database's class factory directly with a connection
+    (None will do for our purposes, since the class factory function
+    we register ignores the connection argument), a non-existent
+    module and class name::
+
+      >>> cls = db.classFactory(None, 'ZODB.not.there', 'atall')
+
+    The class that comes back is a subclass of Broken::
+
+      >>> issubclass(cls, Broken)
+      True
+
+    It implements ILocation and IAnnotations::
+
+      >>> zope.app.location.interfaces.ILocation.isImplementedByInstancesOf(
+      ...       cls)
+      True
+      >>> IAnnotations.isImplementedByInstancesOf(cls)
+      True
+
+    and it has a security checker that is the same as the checker that
+    Broken has::
+
+      >>> (cls.__Security_checker__ is
+      ...     zope.security.checker.getCheckerForInstancesOf(Broken))
+      True
+
+    Cleanup:
+
+      >>> ZODB.broken.broken_cache.clear()    
+    """
     
     Broken_ = Broken # make it local for speed
     find_global = ZODB.broken.find_global
+
+    def type_(name, bases, dict):
+        cls = type(name, bases, dict)
+        checker = zope.security.checker.getCheckerForInstancesOf(Broken_)
+        cls.__Security_checker__ = checker
+        return cls
     
     def classFactory(connection, modulename, globalname):
-        return find_global(modulename, globalname, Broken_)
+        return find_global(modulename, globalname, Broken_, type_)
 
-    event.database.setClassFactory(classFactory)
+    event.database.classFactory = classFactory
 
-installBroken = zope.app.event.function.Subscriber(installBroken)
+installBrokenSubscriber = zope.app.event.function.Subscriber(installBroken)


=== Zope3/src/zope/app/broken/configure.zcml 1.2 => 1.3 ===
--- Zope3/src/zope/app/broken/configure.zcml:1.2	Tue Mar  2 13:50:55 2004
+++ Zope3/src/zope/app/broken/configure.zcml	Thu Mar  4 17:41:47 2004
@@ -3,8 +3,12 @@
     xmlns:event="http://namespaces.zope.org/event"
     >
 
+  <content class=".broken.Broken">
+    <allow interface="zope.app.interfaces.annotation.IAnnotations" />
+  </content>
+
   <event:subscribe
-      subscriber=".broken.installBroken"
+      subscriber=".broken.installBrokenSubscriber"
       event_types="zope.app.event.interfaces.IDatabaseOpenedEvent" 
       />
 




More information about the Zope3-Checkins mailing list