Hi,<br><br>I am using zope.interface in a twisted based project.  I  have found two interrelated unwanted side effects of<br>zope.interface.implements.  Here is a summary and self contained examples that show the problem:<br>
<br>1) The __provides__ attribute propagates * up* an inheritance tree to classes that know nothing of zope.interface.<br><br>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&#39;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.<br>
<br>Example 1: showing how __provides__ propagates up an inheritance tree<br>========================================================<br><br>import zope.interface as zi<br><br>class A(object):<br>    pass<br><br>class IB(zi.Interface):<br>
    pass<br><br>print &quot;At this point _provides__ is NOT in dir(A): &quot;, dir(A)<br>print &quot;And hasattr returns False: &quot;, hasattr(A, &#39;__provides__&#39;)<br><br># Inheriting from A gives A additional attributes like __provides__!<br>
# But A is just a plain old object.<br>class B(A):<br>    zi.implements(IB)<br><br>print &quot;But now, __provides__ is in dir(A): &quot;, dir(A)<br># hasattr(A, &#39;__provides__&#39;) also returns True<br>if hasattr(A, &#39;__provides__&#39;):<br>
    print &quot;A (which is just an object) has been infected with __provides__&quot;<br><br>Example 2: showing how __provides__ messes up dir and inspect.getmembers<br>============================================================<br>
<br>import zope.interface as zi<br><br>class MyBase(object):<br>    <br>    def __new__(cls, *args, **kw):<br>        inst = super(MyBase, cls).__new__(cls, *args, **kw)<br>        print &quot;__provides__ in dir(%s): %s&quot; % (cls.__name__, &#39;__provides__&#39; in dir(cls))<br>
        print &quot;hasattr(%s, &#39;__provides__&#39;): %s&quot; % (cls.__name__, hasattr(cls, &#39;__provides__&#39;))<br>        return inst<br><br>class P(MyBase):<br>    pass<br><br>class IQ(zi.Interface):<br>    pass<br>
<br>class Q(P):<br>    zi.implements(IQ)<br><br># R-&gt;MyBase-&gt;object knows nothing about zope.interface<br>class R(MyBase):<br>    pass<br><br># But, when you create an R, __provides__ is there, but in an inconsistent<br>
# manner.<br>r = R()<br><br># This blows up, even though R is just a MyBase-&gt;object!<br>print &quot;Let&#39;s try inspect.getmembers(R):&quot;<br>import inspect<br>inspect.getmembers(R)<br><br>Summary<br>=======<br><br>
zope.interface.implements should leave base classes that are unrelated to zope.interface (they don&#39;t<br>specify an implements) untouched.<br><br>zope.interface.__provides__ should not raise AttributeError so that classes that do have <br>
the __provides__ attribute always work with inspect.getmembers.<br><br>Cheers,<br><br>Brian<br>