[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