[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