docstring inheritance

HughSW hugh.seckerwalker at gmail.com
Wed Dec 1 21:56:31 EST 2010


Grrrr, sorry about the line wrapping horror; trying again.

class InheritDoc(object):
    """
    Docstring inheriting method descriptor

    The class itself is used as a decorator that creates a class
property for
    the method; the first time the property is used it installs the
method's doc
    and then replaces itself as a class attribute with the method!

    Usage:

    >>> class Foo(object):
    ...     def foo(self, x):
    ...         'Frobber'
    ...         print 'Foo.foo()', x

    Correct usage for overridden method foo(), incorrect usage for
method bar()

    >>> class Bar(Foo):
    ...     @inherit_doc
    ...     def foo(self, x):
    ...         print 'Bar.foo()', x
    ...     @inherit_doc
    ...     def bar(self):
    ...         print 'Bar.bar()'

    >>> Bar.foo.__doc__ == Bar().foo.__doc__ == Foo.foo.__doc__ ==
'Frobber'
    True

    >>> Foo.foo
    <unbound method Foo.foo>
    >>> Foo().foo(10)
    Foo.foo() 10
    >>> Bar.foo
    <unbound method Bar.foo>
    >>> Bar().foo(11)
    Bar.foo() 11

    >>> Bar.bar
    Traceback (most recent call last):
      ...
    NameError: inherit_doc cannot find method 'bar' in parents of
'__main__.Bar'

    >>> Bar().bar
    Traceback (most recent call last):
      ...
    NameError: inherit_doc cannot find method 'bar' in parents of
'__main__.Bar'
    """
    __slots__ = 'inherit_doc_unbound_method'
    def __init__(self, unbound_method):
        self.inherit_doc_unbound_method = unbound_method
    def __get__(self, obj, cls):
        # a self-destructing descriptor/property:
        # the first and only time it's used, it fixes the method's doc
and then
        # replaces itself with the method

        # find the overridden method in mro sequence, skipping the
class itself
        method_name = self.inherit_doc_unbound_method.__name__
        mro_iter = iter(cls.__mro__)
        mro_iter.next()
        for parent in mro_iter:
            overridden = getattr(parent, method_name, None)
            if overridden is not None: break
        if overridden is None:
            raise NameError('inherit_doc cannot find method %r in
parents of %r'
                            % (method_name, '%s.%s'%(cls.__module__,
cls.__name__)))

        # XXX next steps are not threadsafe, maybe not safe at all!
        # set the doc
        self.inherit_doc_unbound_method.__doc__ = overridden.__doc__
        # replace the property with the function
        setattr(cls, method_name, self.inherit_doc_unbound_method)
        # use the replacement
        return getattr(obj if obj is not None else cls, method_name)

inherit_doc = InheritDoc



More information about the Python-list mailing list