[Interface-dev] Problem with zope.interface leaking attributes

Brian Granger ellisonbg.net at gmail.com
Fri Oct 9 12:58:48 EDT 2009


Hi,

I am using zope.interface in a twisted based project.  I  have found two
interrelated unwanted side effects of
zope.interface.implements.  Here is a summary and self contained examples
that show the problem:

1) The __provides__ attribute propagates * up* an inheritance tree to
classes that know nothing of zope.interface.

2) The __provides__ attribute is a descriptor that will sometime raise an
AttributeError even though it is listed in dir(cls).  This means that things
like inspect.getmembers doesn't work.  Because __provides__ propagates *up*
an inheritance tree, inspect.getmember has stopped working on all of my
classes even though they are plain old objects.

Example 1: showing how __provides__ propagates up an inheritance tree
========================================================

import zope.interface as zi

class A(object):
    pass

class IB(zi.Interface):
    pass

print "At this point _provides__ is NOT in dir(A): ", dir(A)
print "And hasattr returns False: ", hasattr(A, '__provides__')

# Inheriting from A gives A additional attributes like __provides__!
# But A is just a plain old object.
class B(A):
    zi.implements(IB)

print "But now, __provides__ is in dir(A): ", dir(A)
# hasattr(A, '__provides__') also returns True
if hasattr(A, '__provides__'):
    print "A (which is just an object) has been infected with __provides__"

Example 2: showing how __provides__ messes up dir and inspect.getmembers
============================================================

import zope.interface as zi

class MyBase(object):

    def __new__(cls, *args, **kw):
        inst = super(MyBase, cls).__new__(cls, *args, **kw)
        print "__provides__ in dir(%s): %s" % (cls.__name__, '__provides__'
in dir(cls))
        print "hasattr(%s, '__provides__'): %s" % (cls.__name__,
hasattr(cls, '__provides__'))
        return inst

class P(MyBase):
    pass

class IQ(zi.Interface):
    pass

class Q(P):
    zi.implements(IQ)

# R->MyBase->object knows nothing about zope.interface
class R(MyBase):
    pass

# But, when you create an R, __provides__ is there, but in an inconsistent
# manner.
r = R()

# This blows up, even though R is just a MyBase->object!
print "Let's try inspect.getmembers(R):"
import inspect
inspect.getmembers(R)

Summary
=======

zope.interface.implements should leave base classes that are unrelated to
zope.interface (they don't
specify an implements) untouched.

zope.interface.__provides__ should not raise AttributeError so that classes
that do have
the __provides__ attribute always work with inspect.getmembers.

Cheers,

Brian
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.zope.org/pipermail/interface-dev/attachments/20091009/1c7bb365/attachment.html 


More information about the Interface-dev mailing list