[Interface-dev] subclasses of classes which implement interfaces
are not documented by pydoc
Jim Fulton
jim at zope.com
Sun Oct 1 09:23:30 EDT 2006
glyph at divmod.com wrote:
> I noticed this issue has come up on the zope3 list recently as well.
>
> Twisted uses pydoctor for generating documentation, and I know that Zope
> uses APIDoc, so I understand that this is not a particularly high
> priority issue. I can also see that pydoc's implementation is...
> questionable, at best, due to the way it semi-randomly throws away any
> error information.
>
> However, I tracked down the problem a bit, so perhaps these
> investigations will serve useful:
Thanks for digging into this.
> The problem, as described in the topic, can be expressed by this code:
>
> # dontdocme.py
> from zope.interface import Interface, implements
>
> class IDestroyDocs(Interface):
> """
> I am a random interface.
> """
>
> class A:
> """
> I implement a thing.
> """
> implements(IDestroyDocs)
>
> class B(A):
> """
> Voila: I have no documentation.
> """
> # Without the following line, this class will not work with pydoc:
> # implements(IDestroyDocs)
>
>
> "help(B)" at an interactive interpreter or "pydoc dontdocme.B" at a
> commandline will not show any information about B.
>
> If you look down in the guts of pydoc for what's happening, it's due to
> the fact that attributes of A aren't showing up on B. I think that in
> reality this is a bug in pydoc, but it seems that it might break other
> code.
Yes. A common mistake in class-introspection code is to assume that is a class
has a key in it's dictionary (or in the dictionary of one of its ancestors,
that it has a corresponding attribute. This isn't true in general.
>>>> pydoc.text.docclass(dontdocme.B)
> Traceback (most recent call last):
> File "<stdin>", line 1, in ?
> File "C:\Python24\lib\pydoc.py", line 1170, in docclass
> inspect.classify_class_attrs(object))
> File "C:\Python24\lib\inspect.py", line 211, in classify_class_attrs
> obj = getattr(cls, name)
> AttributeError: __provides__
>
> Pydoc then erroneously catches AttributeError from this code and falls
> back to a simplistic str() based approach. Really this is a special
> case of the following:
>
>>>> dontdocme.A.__provides__.__get__(None, dontdocme.A)
> <zope.interface.declarations.ClassProvides object at 0x00AFCFD0>
>>>> dontdocme.A.__provides__.__get__(None, dontdocme.B)
> Traceback (most recent call last):
> File "<stdin>", line 1, in ?
> AttributeError: __provides__
>
> It's not really clear to me why this works this way; IDestroyDocs is
> implemented by B as well as A due to inheritance, so why aren't its
> various magical attributes visible there as well? I realize these are
> implementation details, but the behavior seems inconsistent unless B
> also needed to explicitly declare all the interfaces it implemented.
This is a good question. You are right that __provides__ is an internal
attribute. If one were to use the proper, providedBy on A and B, you would get
equivalent answers. For example:
print list(providedBy(A))
print list(providedBy(B))
prints 2 empty lists.
The intent is that declaring that a class provides an interface says
nothing about it's subclasses. (Some people don't agree with this
intent.)
When you make any declarations about a class, internal descriptors
are set up for it. In the example above, a __provides__ descriptor
for A is established that returns an empty ClassProvides specification.
To prevent inheritence, the internal __provides__ descriptor bothers to
prevent inheritance by raising an AttributeError if it is used on a class
other than the one it was defined for. I suppose that, alternatively it
could either:
- Return an empty ClassProvides specification or
- Initialize the class' interface meta data.
The former change is easier and almost certainly adequate.
This would work around the common bug in introspection
systems. (A Zope-internal introspection facility had the same bug.)
Would you mind submitting a bug report:
https://launchpad.net/products/zope.interface/+bugs
Jim
--
Jim Fulton mailto:jim at zope.com Python Powered!
CTO (540) 361-1714 http://www.python.org
Zope Corporation http://www.zope.com http://www.zope.org
More information about the Interface-dev
mailing list