Welcome, guest | Sign In | My Account | Store | Cart
def get_docstring(bases, name):
    for base in bases:
        if name not in base.__dict__:
            continue
        attr = getattr(base, name)
        if not hasattr(attr, "__doc__"):
            continue
        if attr.__doc__ is None:
            continue
        return attr.__doc__
    return None


def inherits_docstring_func(f, cls=None, funcname=None):
    """A function decorator for inheriting function docstrings.

    Look to cls for the docstring to inherit.  The funcname argument
    indicates that the cls should be searched for that name instead
    of f.__name__.

    """

    name = funcname
    if not name:
        name = f.__name__
    if cls is None:
        """shouldn't get here"""

    # go for it

    if funcname:
        docstring = get_docstring((cls,), name)
    else:
        docstring = None

    if docstring is None:
        docstring = get_docstring(cls.__bases__, name)
    if docstring is None and hasattr(cls, "__implements__"):
        # for registrations on ABCs
        docstring = get_docstring(cls.__implements__, name)

    if docstring is not None:
        f.__doc__ = docstring
    return f


def inherits_docstring(f, cls=None, funcname=None):
    """A decorator for inheriting function docstrings.

    If f is a class, return a decorator that looks to the class for
    the docstring to inherit.

    """
    if isinstance(f, type):
        #passed a class, so return a decorator
        cls = f
        def decorator(func):
            return inherits_docstring(func, cls)
        return decorator

    # otherwise used as decorator
    if cls is None:
        # don't know how to do this without a metaclass
        raise NotImplementedError
    return inherits_docstring_func(f, cls, funcname)


class DocDeco:
    """A class decorator tool for inheriting method docstrings.

    """

    class MethodWrapper:
        """decorator"""
        def __init__(self, f):
            self.f = f
    inherits_docstring = MethodWrapper

    def helps_docstrings(cls):
        """The class decorator."""

        for name, obj in cls.__dict__.items():
            if not isinstance(obj, DocDeco.MethodWrapper):
                # only act on decorated methods
                continue

            f = inherits_docstring(obj.f, cls)
            setattr(cls, name, f)

        return cls


class DocMeta(type):
    """A metaclass for inheriting method docstrings.

    """

    class MethodWrapper:
        """decorator"""
        def __init__(self, f):
            self.f = f
    inherits_docstring = MethodWrapper

    def __init__(cls, name, bases, namespace):
        super().__init__(name, bases, namespace)

        for name, obj in namespace.items():
            if not isinstance(obj, cls.MethodWrapper):
                # only act on decorated methods
                continue

            f = inherits_docstring(obj.f, cls)
            setattr(cls, name, f)

Diff to Previous Revision

--- revision 1 2011-06-09 05:36:36
+++ revision 2 2011-06-09 06:16:44
@@ -1,38 +1,113 @@
-"""docgiver module"""
+def get_docstring(bases, name):
+    for base in bases:
+        if name not in base.__dict__:
+            continue
+        attr = getattr(base, name)
+        if not hasattr(attr, "__doc__"):
+            continue
+        if attr.__doc__ is None:
+            continue
+        return attr.__doc__
+    return None
 
-import types
-import modulehacker
 
-class DocGiver(modulehacker.Hacker):
-    def fix_classdoc(self, cls):
-        if cls.__doc__:
-            return
-        for base in cls.__mro__[1:]:
-            if base.__doc__:
-                cls.__doc__ = base.__doc__
-                break
+def inherits_docstring_func(f, cls=None, funcname=None):
+    """A function decorator for inheriting function docstrings.
 
-    def fix_methoddoc(self, cls):
-        for attr in dir(cls):
-            method = getattr(cls, attr)
-            if not isinstance(method, types.FunctionType):
+    Look to cls for the docstring to inherit.  The funcname argument
+    indicates that the cls should be searched for that name instead
+    of f.__name__.
+
+    """
+
+    name = funcname
+    if not name:
+        name = f.__name__
+    if cls is None:
+        """shouldn't get here"""
+
+    # go for it
+
+    if funcname:
+        docstring = get_docstring((cls,), name)
+    else:
+        docstring = None
+
+    if docstring is None:
+        docstring = get_docstring(cls.__bases__, name)
+    if docstring is None and hasattr(cls, "__implements__"):
+        # for registrations on ABCs
+        docstring = get_docstring(cls.__implements__, name)
+
+    if docstring is not None:
+        f.__doc__ = docstring
+    return f
+
+
+def inherits_docstring(f, cls=None, funcname=None):
+    """A decorator for inheriting function docstrings.
+
+    If f is a class, return a decorator that looks to the class for
+    the docstring to inherit.
+
+    """
+    if isinstance(f, type):
+        #passed a class, so return a decorator
+        cls = f
+        def decorator(func):
+            return inherits_docstring(func, cls)
+        return decorator
+
+    # otherwise used as decorator
+    if cls is None:
+        # don't know how to do this without a metaclass
+        raise NotImplementedError
+    return inherits_docstring_func(f, cls, funcname)
+
+
+class DocDeco:
+    """A class decorator tool for inheriting method docstrings.
+
+    """
+
+    class MethodWrapper:
+        """decorator"""
+        def __init__(self, f):
+            self.f = f
+    inherits_docstring = MethodWrapper
+
+    def helps_docstrings(cls):
+        """The class decorator."""
+
+        for name, obj in cls.__dict__.items():
+            if not isinstance(obj, DocDeco.MethodWrapper):
+                # only act on decorated methods
                 continue
-            if method.__doc__:
+
+            f = inherits_docstring(obj.f, cls)
+            setattr(cls, name, f)
+
+        return cls
+
+
+class DocMeta(type):
+    """A metaclass for inheriting method docstrings.
+
+    """
+
+    class MethodWrapper:
+        """decorator"""
+        def __init__(self, f):
+            self.f = f
+    inherits_docstring = MethodWrapper
+
+    def __init__(cls, name, bases, namespace):
+        super().__init__(name, bases, namespace)
+
+        for name, obj in namespace.items():
+            if not isinstance(obj, cls.MethodWrapper):
+                # only act on decorated methods
                 continue
-            for base in cls.__mro__[1:]:
-                if attr not in dir(base):
-                    continue
-                m = getattr(base, attr)
-                if isinstance(m, types.FunctionType) and m.__doc__:
-                    method.__doc__ = m.__doc__
-                break
 
-    def hack(self, module):
-        for attr in dir(module):
-            cls = getattr(module, attr)
-            if isinstance(cls, type):
-                #self.fix_classdoc(cls)
-                self.fix_methoddoc(cls)
-        return module
-
-modulehacker.register(DocGiver())
+            f = inherits_docstring(obj.f, cls)
+            setattr(cls, name, f)

History