[Zope3-checkins] CVS: Zope3/src/zope/app - context.py:1.10.2.1 context.txt:1.6.2.1 zapi.py:1.6.2.1 _app.py:1.10.2.1 attributeannotations.py:1.2.26.1 copypastemove.py:1.7.2.1 dependable.py:1.3.26.1 introspector.py:1.5.10.1 size.py:1.5.24.1

Grégoire Weber zope@i-con.ch
Sun, 22 Jun 2003 10:24:05 -0400


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

Modified Files:
      Tag: cw-mail-branch
	_app.py attributeannotations.py copypastemove.py dependable.py 
	introspector.py size.py 
Added Files:
      Tag: cw-mail-branch
	context.py context.txt zapi.py 
Log Message:
Synced up with HEAD

=== Added File Zope3/src/zope/app/context.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 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.
#
##############################################################################
"""Wrapping/proxy coordination

Specifically, coordinate use of context wrappers and security proxies.

Revision information:
$Id: context.py,v 1.10.2.1 2003/06/22 14:22:33 gregweb Exp $
"""

from pickle import PicklingError
from zope.app.interfaces.context import IContextWrapper, IZopeContextWrapper
from zope.component import queryAdapter
from zope.context.wrapper import getcontext, setcontext, getdictcreate
from zope.context.wrapper import Wrapper as BaseWrapper
from zope.interface.declarations import getObjectSpecification
from zope.interface.declarations import ObjectSpecification
from zope.interface.declarations import ObjectSpecificationDescriptor
from zope.interface import moduleProvides, implements, providedBy
from zope.proxy import queryProxy, getProxiedObject
from zope.security.checker import defineChecker, BasicTypes
from zope.security.checker import selectChecker, CombinedChecker, NoProxy
from zope.security.proxy import Proxy, getChecker

moduleProvides(IContextWrapper)
__all__ = tuple(IContextWrapper)
__metaclass__ = type

class DecoratorSpecificationDescriptor(ObjectSpecificationDescriptor):
    """Support for interface declarations on decorators

    >>> from zope.interface import *
    >>> class I1(Interface):
    ...     pass
    >>> class I2(Interface):
    ...     pass
    >>> class I3(Interface):
    ...     pass
    >>> class I4(Interface):
    ...     pass

    >>> class D1(Wrapper):
    ...   implements(I1)


    >>> class D2(Wrapper):
    ...   implements(I2)

    >>> class X:
    ...   implements(I3)

    >>> x = X()
    >>> directlyProvides(x, I4)

    Interfaces of X are ordered with the directly-provided interfaces first

    >>> [interface.__name__ for interface in list(providedBy(x))]
    ['I4', 'I3']

    When we decorate objects, what order should the interfaces come
    in?  One could argue that decorators are less specific, so they
    should come last.

    >>> [interface.__name__ for interface in list(providedBy(D1(x)))]
    ['I4', 'I3', 'I1']

    >>> [interface.__name__ for interface in list(providedBy(D2(D1(x))))]
    ['I4', 'I3', 'I1', 'I2']
    """
    def __get__(self, inst, cls=None):
        if inst is None:
            return getObjectSpecification(cls)
        else:
            provided = providedBy(getProxiedObject(inst))

            # Use type rather than __class__ because inst is a proxy and
            # will return the proxied object's class.
            cls = type(inst) 
            return ObjectSpecification(provided, cls)


class DecoratedSecurityCheckerDescriptor:
    """Descriptor for a Wrapper that provides a decorated security checker.
    """
    def __get__(self, inst, cls=None):
        if inst is None:
            return self
        else:
            proxied_object = getProxiedObject(inst)
            checker = getattr(proxied_object, '__Security_checker__', None)
            if checker is None:
                checker = selectChecker(proxied_object)
            wrapper_checker = selectChecker(inst)
            if wrapper_checker is None:
                return checker
            elif checker is None:
                return wrapper_checker
            else:
                return CombinedChecker(wrapper_checker, checker)


class Wrapper(BaseWrapper):
    """Zope-specific context wrapper
    """
    __slots__ = ()

    def __reduce_ex__(self, proto=None):
        raise PicklingError, "Zope context wrappers cannot be pickled"

    __reduce__ = __reduce_ex__

    __providedBy__ = DecoratorSpecificationDescriptor()

    __Security_checker__ = DecoratedSecurityCheckerDescriptor()


def ContextWrapper(_ob, _parent, **kw):
    if type(_ob) in BasicTypes:
        # Don't wrap basic objects
        return _ob

    wrapper = queryProxy(_ob, Wrapper)
    if wrapper is not None: # using kw as marker

        if _parent is getcontext(wrapper):
            # This would be a redundant wrapper. We'll just use the
            # one we've got.

            # But we want tp make sure we have the same data
            if kw:
                getdictcreate(wrapper).update(kw)
            return _ob

    if type(_ob) is Proxy:
        # insert into proxies
        checker = getChecker(_ob)
        _ob = getProxiedObject(_ob)
    else:
        checker = None

    if wrapper is not None:
        # we were already wrapped, use the same class
        _ob = type(wrapper)(_ob, _parent, **kw)
    else:
        adapter = queryAdapter(_ob, IZopeContextWrapper)
        if adapter is not None:
            _ob = adapter
            setcontext(_ob, _parent)
            if kw:
                getdictcreate(_ob).update(kw)
        else:
            # No specific adapter, fall back to Wrapper
            _ob = Wrapper(_ob, _parent, **kw)

    if checker is not None:
        # XXX Problem here is if the wrapper requires a different checker
        # Let's make a combined checker using the checker we have.
        # This is similar to what the DecoratedSecurityCheckerDescriptor
        # does. (See above.)
        # This behaviour needs a test.
        wrapper_checker = selectChecker(_ob)
        if wrapper_checker is not None:
            checker = CombinedChecker(wrapper_checker, checker)
        _ob = Proxy(_ob, checker)

    return _ob

defineChecker(Wrapper, NoProxy)

def getItem(collection, name):
    return ContextWrapper(collection[name], collection, name=name)

def getAttr(collection, name):
    return ContextWrapper(getattr(collection, name), collection, name=name)

def queryItem(collection, name, default=None):
    return ContextWrapper(collection.get(name, default),
                          collection, name=name)

def queryAttr(collection, name, default=None):
    return ContextWrapper(getattr(collection, name, default),
                          collection, name=name)


=== Added File Zope3/src/zope/app/context.txt ===
Context Decorators
==================

Introduction
------------

Sorry. We should have a general description of context wrappers and
decorators here, but all we've got are some issues that we're
wrestling with.

Until we've written a clear description, the following irc dialog is
instructive:: 

  <SteveA> So... Decorators.

  <SteveA> Before I talk about decorators, I need to spend a little time
  talking about context wrappers.

  <SteveA> As you know, zope 3 doesn't do implicit acquisition like zope
  2 does.

  <bigkevmcd> SteveA: is it worth pointing out a source file, to look
  at...?

  <SteveA> That is, if I have a folder f that contains a document d,
  f.d.items() will not be equivalent to f.items()

  <SteveA> (assuming that a folder has an items method)

  * faassen listens in. :)

  <mexiKON> SteveA: yeah, i read the wiki page about basic context
  wrappers

  <SteveA> This is for the better, as it gets rid of the indeterminate
  nature of implicit acquisition

  <SteveA> however, even though we don't want or need implicit
  acquisition in zope 3, we still need some way of recording the
  "context" of a particular journey through the content.

  <mexiKON> right, through context wrappers

  <SteveA> we need this because we want to make policy decisions, and
  provide different software and settings, at different places

  <mexiKON> like for 'playful' utilities

  <SteveA> for example, we might want to install two different versions
  of a software package in different parts of a site

  <SteveA> or to customise them differently

  <SteveA> right, this is like local utilities

  <faassen> or two different frontends on websites, a traditional use
  for acquisition in zope 2

  <SteveA> we've stopped using the terms "placeful" and "placeless" in
  favour of "local" and "global"

  <SteveA> faassen: actually, that's a bit different

  <faassen> SteveA: wouldn't that be a set of views associated ..um,
  localfully? :)

  <SteveA> you'd use a different publishing traversal component for
  that, which would set a different skin to use

  <SteveA> but the context, as far as services etc. are concerned, would
  be the same

  <faassen> SteveA: hm.

  <SteveA> So, the way we remember the traversal to a particular piece
  of content is by looking in its context wrapper

  <SteveA> we can get from the wrapper the names used at each step in
  the traversal, and each of the "parent" objects, all the way down to
  the root

  <SteveA> you can use what you get from the context wrapper to do the
  equivalent of implicit acquisition, but do it explicitly

  <SteveA> The way context wrappers work is this:

  <SteveA> >>> o = SomeContentObject()

  <SteveA> >>> wrapped_o = ContextWrapper(o)

  <SteveA> >>> wrapped_o.somemethod() # passes through the
  call. Equivalent to o.somemethod()

  <SteveA> So, you see that a context wrapper is like a transparent
  wrapper around the object.

  <SteveA> A decorator is a context wrapper that isn't quite so
  transparent.

  <mexiKON> what does it not let thru?

  <bigkevmcd> or what does it let through?

  <SteveA> That is, for some methods or attributes, the wrapper itself
  handles the method call / attribute lookup

  <bigkevmcd> as it's a fixed set

  <SteveA> Take a look at src/zope/app/container/zopecontainer.py

  <SteveA>
  http://cvs.zope.org/Zope3/src/zope/app/container/zopecontainer.py?rev=HEAD&content-type=text/vnd.viewcvs-markup

  <SteveA> The first class in the file is ZopeContainerAdapter. Don't
  bother about that.

  <SteveA> About half way down, there is ZopeContainerDecorator.

  <SteveA> You can see that it derives from Wrapper. That is, it is a
  kind of context wrapper.

  <SteveA> It implements(IZopeContainer). Decorators are set up so that
  if you say that the class implements some interface, a wrapped object
  will provide whatever the object provides, plus what the decorator
  provides.

  <SteveA> Each of the methods in ZopeContainerDecorator are handled by
  the decorator (that is, by the wrapper), rather than by the object
  that is wrappe.

  <SteveA> Each of the methods in ZopeContainerDecorator are handled by
  the decorator (that is, by the wrapper), rather than by the object
  that is wrapped.

  <SteveA> If you look at the first method, __getitem__, you see that it
  passes the call to __getitem__ through to the proxied object, but
  rather than return the retrieved item, it returns the item in a
  context-wrapper.

  <SteveA> This is helpful when you are working with containers, as, if
  you have a context-wrapped container, when you get one of its
  subobjects, it too is context wrapped. So, getPath and getting
  services for that subobject will work as expected.

  <SteveA> Writing using decorators is another way to keep your content
  classes looking like ordinary python, and putting zope-specific
  functionality in a separate place.

  <SteveA> this makes it easier to write tests, easier to see what is
  going on, easier to use third-party python classes with zope

  <bigkevmcd> by developing the content in python, and then "decorating"
  it with Zope behaviour via a Decorator?

  <SteveA> right


Issues
------

* How to decide what permssions to use for new methods introduced in
  the decorator?

  Consider a ZopeContainerDecorator. It has a method 'rename' that does not
  appear in IContainer. What permission should guard 'rename'?
  'rename' depends on 'setObject' in IContainer. Different content components
  protect 'setObject' with different permissions; for example,
  zope.ManageContent or zope.ManageServices.
  So, we can't guard 'rename' with one hard-coded permission.

  What could we do instead?

  - Reorder proxies, decorator outside the security proxy.
    We could somehow re-order the proxies around an object so that the decorator
    goes on the outside. This is awkward, as it breaks our invariant of putting
    the security proxy always on the outside. There are also efficiency issues
    if the interface-related descriptors are security-proxied.

    Let's analyze this a bit further.  

    * Why do we have an invariant that security proxies always go on the
      outside?  I'm not sure I know. I think it may be:

      + Context methods and methods of ContextAware classes get rebound
      to wrapper. They don't generally expect to be bound to security
      proxies.  In particular, it's common for context methods to rely
      on access to private data.

      + Maybe it simplified wrapper manipulation. I *think* recent
      changes to basic proxy introspection make this a non issue.

    * Adapters commonly are put around proxied objects.

      I see decorators lying along a continuum from totally transparent
      proxies to adapters.  Given, this, I'm not positive that we have
      such an invariant.

    * It would be bad for interface descriptors to end up on the wrong
      side of security proxies.  Security descriptors always need to
      be bound to objects wo security proxies.

      Note that interface descriptors can deal with context wrappers
      now, but they would go faster if they didn't need to.

      If we didn't have the ContextAware mix-in, we wouldn't need to
      worry about effects on interface descriptors, because they
      wouldn't evey be magically converted to context descriptors.

    * Is there a helpful rule that's less general than "security
      proxies" always go on the outside?

      + I think this has to do with how intrinsic something is.

        A descriptor from a class implementation should have full
        access to the implementation.  If adapters could be registered
        for classes, rather than interfaces, then the adapter could
        have full access to the implementation.  An adapter from a
        __conform__ should have access to the interface.

        Adapters registered for an interface should only have access
        to the interface.

        This reveals, I think that class-based adapter registration is 
        qualitatively different than interface-based registration.

  - What protects rename should be what protects setObject.
    We could declare that rename is to be protected with whatever protects the
    'setObject' operation on the proxied object.
    That makes the zcml more complex, and special for decorators.
    That also makes the checker to use for decorators more complex and special.

  - Rename gets proxied by magic in the decorator.
    We could declare that rename is a special "untrusted" method, and cause
    its 'self' argument to be bound not to the decorator instance, but to
    some special object that is like the original decorator, but which wraps
    a security-proxied object.

  - Register decorators to classes rather than interfaces.
    Security declarations are made by class, not by interface, so it makes sense
    for a decorator that needs particular security declarations to be declared
    for a class, and not an interface.
    It is not possible, currently, to register an adapter for a class.
    If it is made possible to do this, adapters registered for classes would
    always trump those registered for interfaces.

* ContextAwareDescriptors class advice

  You can make all descriptors defined in a particular class into
  context-aware descriptors by using the ContextAwareDescriptors() function
  within the class suite. For example::

      class FooBaseClass:
          def m0(self, ...)

      class Foo(FooBaseClass):
          ContextAwareDescriptors()
          implements(IFoo)

          def m1(self, ...): ...

          def m2(self, ...): ...

          ...

          p = property(_getP, _setP)

  In this case, all of the methods defined in Foo, such as m1, m2, and
  we assume _getP and _setP, will be made into the equivalent of
  ContextMethods.
  Properties such as p will be made into the equivalent of ContextProperties.
  However, m0, inherited from FooBaseClass, will remain a normal
  instance method.

  If a ContextMethod or other ContextDescriptor is used in Foo, then
  it will be left exactly as it is.

  The ContextAwareDescriptors class advice is better than using a marker
  base-class because with the class advice, you always will be able to see
  that the descriptors of a class will be made context-aware.
  With the base-class approach, descriptors could be unpredictably converted
  into context-aware descriptors through deriving new classes.
  Such unpredictability and implicitness is bad.



=== Added File Zope3/src/zope/app/zapi.py ===
##############################################################################
#
# Copyright (c) 2003 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.
#
##############################################################################
"""Collection of many common api functions

Makes imports easier

$Id: zapi.py,v 1.6.2.1 2003/06/22 14:22:33 gregweb Exp $
"""

from zope.app.interfaces.zapi import IZAPI
from zope.interface import moduleProvides
from zope.context import getWrapperData

moduleProvides(IZAPI)
__all__ = tuple(IZAPI)

from zope.component import *
from zope.context import *
from zope.app.context import *
from zope.app.traversing import *

name = getName


=== Zope3/src/zope/app/_app.py 1.10 => 1.10.2.1 ===
--- Zope3/src/zope/app/_app.py:1.10	Tue May 20 16:24:30 2003
+++ Zope3/src/zope/app/_app.py	Sun Jun 22 10:22:33 2003
@@ -81,7 +81,7 @@
         if db is None and config_file is None:
             db = 'Data.fs'
             config_file = 'site.zcml'
-        
+
         if config_file is not None:
             config(config_file)
         self.db = database(db)
@@ -91,7 +91,7 @@
 
         The object returned is connected to an open database connection.
         """
-        
+
         from zope.app.publication.zopepublication import ZopePublication
         return self.db.open().root()[ZopePublication.root_name]
 


=== Zope3/src/zope/app/attributeannotations.py 1.2 => 1.2.26.1 ===
--- Zope3/src/zope/app/attributeannotations.py:1.2	Wed Dec 25 09:12:24 2002
+++ Zope3/src/zope/app/attributeannotations.py	Sun Jun 22 10:22:33 2003
@@ -18,16 +18,16 @@
 
 from zodb.btrees.OOBTree import OOBTree
 from zope.app.interfaces.annotation import IAnnotations
-from zope.proxy.introspection import removeAllProxies
-from zope.proxy.context import ContextWrapper
+from zope.proxy import removeAllProxies
+from zope.app.context import ContextWrapper
+from zope.interface import implements
 
 class AttributeAnnotations:
     """
     Store annotations in the __annotations__ attribute on a
     IAttributeAnnotatable object.
     """
-
-    __implements__ = IAnnotations
+    implements(IAnnotations)
 
     def __init__(self, obj):
         # We could remove all proxies from obj at this point, but


=== Zope3/src/zope/app/copypastemove.py 1.7 => 1.7.2.1 ===
--- Zope3/src/zope/app/copypastemove.py:1.7	Wed May 21 16:27:41 2003
+++ Zope3/src/zope/app/copypastemove.py	Sun Jun 22 10:22:33 2003
@@ -17,7 +17,7 @@
 $Id$
 """
 
-from zope.app.traversing import getParent, objectName, getPath
+from zope.app.traversing import getParent, getName, getPath
 from zope.component import getAdapter, queryAdapter
 from zope.app.interfaces.copypastemove import IObjectMover
 from zope.app.interfaces.copypastemove import IObjectCopier
@@ -32,12 +32,13 @@
 from zope.app.interfaces.container import IPasteTarget
 from zope.app.event.objectevent import ObjectMovedEvent, ObjectCopiedEvent
 from zope.app.event import publish
-from zope.proxy.introspection import removeAllProxies
+from zope.proxy import removeAllProxies
+from zope.interface import implements
 
 class ObjectMover:
     '''Use getAdapter(obj, IObjectMover) to move an object somewhere.'''
 
-    __implements__ = IObjectMover
+    implements(IObjectMover)
 
     def __init__(self, object):
         self.context = object
@@ -50,7 +51,7 @@
 
         obj = self.context
         container = getParent(obj)
-        orig_name = objectName(obj)
+        orig_name = getName(obj)
         if new_name is None:
             new_name = orig_name
 
@@ -95,13 +96,13 @@
         '''
         obj = self.context
         if name is None:
-            name = objectName(obj)
+            name = getName(obj)
         pastetarget = getAdapter(target, IPasteTarget)
         return pastetarget.acceptsObject(name, obj)
 
 class ObjectCopier:
 
-    __implements__ = IObjectCopier
+    implements(IObjectCopier)
 
     def __init__(self, object):
         self.context = object
@@ -119,7 +120,7 @@
         """
         obj = self.context
         container = getParent(obj)
-        orig_name = objectName(obj)
+        orig_name = getName(obj)
         if new_name is None:
             new_name = orig_name
 
@@ -158,14 +159,14 @@
         '''
         obj = self.context
         if name is None:
-            name = objectName(obj)
+            name = getName(obj)
         pastetarget = getAdapter(target, IPasteTarget)
         return pastetarget.acceptsObject(name, obj)
 
 
 class NoChildrenObjectCopier(ObjectCopier):
 
-    __implements__ = INoChildrenObjectCopier
+    implements(INoChildrenObjectCopier)
 
     def __init__(self, object):
         self.context = object
@@ -183,7 +184,7 @@
         """
         obj = self.context
         container = getParent(obj)
-        orig_name = objectName(obj)
+        orig_name = getName(obj)
         if new_name is None:
             new_name = orig_name
 


=== Zope3/src/zope/app/dependable.py 1.3 => 1.3.26.1 ===
--- Zope3/src/zope/app/dependable.py:1.3	Mon Dec 30 16:41:41 2002
+++ Zope3/src/zope/app/dependable.py	Sun Jun 22 10:22:33 2003
@@ -19,31 +19,83 @@
 
 from zope.app.interfaces.dependable import IDependable
 from zope.app.interfaces.annotation import IAnnotations
+from zope.app.traversing import getParent, canonicalPath, getPath
 from zope.component import getAdapter
+from zope.interface import implements
 
-key = 'zope.app.dependable.Dependents'
 
-class Dependable:
-    __doc__ = IDependable.__doc__
+class PathSetAnnotation:
 
-    __implements__ =  IDependable
+    """Abstract base class for annotations that are sets of paths.
+
+    To make this into a concrete class, a subclass must set the class
+    attribute 'key' to a unique annotation key.  A subclass may also
+    choose to rename the methods.
+    """
 
     def __init__(self, context):
         self.context = context
+        try:
+            pp = getPath(getParent(self.context))
+            if not pp.endswith("/"):
+                pp += "/"
+            self.pp = pp # parentpath
+        except TypeError:
+            self.pp = ""
+        self.pplen = len(self.pp)
 
-    def addDependent(self, location):
-        "See IDependable"
+    def addPath(self, path):
+        path = self._make_relative(path)
         annotations = getAdapter(self.context, IAnnotations)
-        annotations [key] = annotations.get(key, ()) + (location, )
+        old = annotations.get(self.key, ())
+        fixed = map(self._make_relative, old)
+        if path not in fixed:
+            fixed.append(path)
+        new = tuple(fixed)
+        if new != old:
+            annotations[self.key] = new
 
-    def removeDependent(self, location):
-        "See IDependable"
+    def removePath(self, path):
+        path = self._make_relative(path)
         annotations = getAdapter(self.context, IAnnotations)
-        annotations[key] = tuple([loc
-                                  for loc in annotations.get(key, ())
-                                  if loc != location])
+        old = annotations.get(self.key, ())
+        if old:
+            fixed = map(self._make_relative, old)
+            fixed = [loc for loc in fixed if loc != path]
+            new = tuple(fixed)
+            if new != old:
+                if new:
+                    annotations[self.key] = new
+                else:
+                    del annotations[self.key]
 
-    def dependents(self):
-        "See IDependable"
+    def getPaths(self):
         annotations = getAdapter(self.context, IAnnotations)
-        return annotations.get(key, ())
+        locs = annotations.get(self.key, ())
+        return tuple(map(self._make_absolute, locs))
+
+    def _make_relative(self, path):
+        if path.startswith("/") and self.pp:
+            path = canonicalPath(path)
+            if path.startswith(self.pp):
+                path = path[self.pplen:]
+                while path.startswith("/"):
+                    path = path[1:]
+        return path
+
+    def _make_absolute(self, path):
+        if not path.startswith("/") and self.pp:
+            path = self.pp + path
+        return path
+
+
+class Dependable(PathSetAnnotation):
+    """See IDependable."""
+
+    implements(IDependable)
+
+    key = "zope.app.dependable.Dependents"
+
+    addDependent = PathSetAnnotation.addPath
+    removeDependent = PathSetAnnotation.removePath
+    dependents = PathSetAnnotation.getPaths


=== Zope3/src/zope/app/introspector.py 1.5 => 1.5.10.1 ===
--- Zope3/src/zope/app/introspector.py:1.5	Thu May  1 15:35:02 2003
+++ Zope3/src/zope/app/introspector.py	Sun Jun 22 10:22:33 2003
@@ -16,15 +16,15 @@
 
 from zope.app.interfaces.introspector import IIntrospector
 from zope.app.interfaces.services.module import IModuleService
-from zope.component import getServiceManager, getAdapter, \
-     getServiceDefinitions
-from zope.proxy.introspection import removeAllProxies
+from zope.component import getServiceManager, getAdapter, getServiceDefinitions
+from zope.proxy import removeAllProxies
+from zope.interface import implements, implementedBy
 
 
 class Introspector:
     """Introspects an object"""
 
-    __implements__ = IIntrospector
+    implements(IIntrospector)
 
     def __init__(self, context):
         self.context = context
@@ -91,12 +91,7 @@
 
     def getInterfaces(self):
         """Returns interfaces implemented by this class"""
-        interfaces = removeAllProxies(self.currentclass).__implements__
-        if type(interfaces) != tuple:
-            interfaces = (interfaces,)
-        else:
-            interfaces = self._unpackTuple(interfaces)
-        return interfaces
+        return tuple(implementedBy(removeAllProxies(self.currentclass)))
 
     def getInterfaceNames(self):
         names = []
@@ -138,7 +133,7 @@
         bases = self._unpackTuple((self.currentclass).__bases__)
         return bases
 
-    def getInterfaceConfiguration(self):
+    def getInterfaceRegistration(self):
         """Returns details for a interface configuration"""
         #sm = queryServiceManager(self.context)
         service = []


=== Zope3/src/zope/app/size.py 1.5 => 1.5.24.1 ===
--- Zope3/src/zope/app/size.py:1.5	Fri Jan 17 08:23:15 2003
+++ Zope3/src/zope/app/size.py	Sun Jun 22 10:22:33 2003
@@ -17,13 +17,13 @@
 """
 
 from zope.app.interfaces.size import ISized
+from zope.interface import implements
 
 __metaclass__ = type
 
 class DefaultSized:
+    implements(ISized)
 
-    __implements__ = ISized
-    
     def __init__(self, obj):
         try:
             size = int(obj.getSize())
@@ -35,7 +35,7 @@
     def sizeForSorting(self):
         """See ISized"""
         return self._sortingSize
-        
+
     def sizeForDisplay(self):
         """See ISized"""
         units, size = self._sortingSize