Skip to content

Instantly share code, notes, and snippets.

@a-recknagel
Last active December 10, 2019 12:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save a-recknagel/de864922bd4183cf523a2463a2da5f3d to your computer and use it in GitHub Desktop.
Save a-recknagel/de864922bd4183cf523a2463a2da5f3d to your computer and use it in GitHub Desktop.
inherit docs from superclasses via decorator
import types
def inherit_docstrings(_cls=None, *, overload=True):
def wrap(cls):
for name, member in vars(cls).items():
if not isinstance(member, types.FunctionType):
continue # only consider methods
if member.__doc__:
continue # skip documented methods
# traverse parents
for base_cls in cls.mro()[1:]:
if name not in vars(base_cls):
continue # it needs to be the same method
parent_func = vars(base_cls)[name]
if not parent_func.__doc__:
continue # ignore parents without docstrings
if not overload and parent_func.__code__ != member.__code__:
continue # ignore parent docstrings if overload=False and the method was overloaded
member.__doc__ = parent_func.__doc__
break
return cls
# cute trick that allows dropping the round brackets when calling an arg-less wrapper
if _cls is None:
return wrap
return wrap(_cls)
# test cases
class Foo:
def foo(self):
"""print a foo"""
print("foo")
@inherit_docstrings
class Bar(Foo):
pass
@inherit_docstrings
class Baz(Foo):
def foo(self):
print("baz")
@inherit_docstrings(overload=False)
class Qux(Foo):
def foo(self):
print("qux")
@inherit_docstrings
class Quux(Qux):
def foo(self):
print("quux")
# base case
print(f"{Foo.foo.__doc__=}") # Foo.foo.__doc__='print a foo'
# simple inheritance of docs, doesn't even needs to decorator
print(f"{Bar.foo.__doc__=}") # Bar.foo.__doc__='print a foo'
# inheriting docs despite overloading method
print(f"{Baz.foo.__doc__=}") # Baz.foo.__doc__='print a foo'
# disabling inheritance of docs for overloaded methods
print(f"{Qux.foo.__doc__=}") # Qux.foo.__doc__=None
# fallback to a parent that has a docstring for the overloaded method
print(f"{Quux.foo.__doc__=}") # Quux.foo.__doc__='print a foo'
@a-recknagel
Copy link
Author

note: overload=False doesn't really do anything useful. Most of the cases where you'd set it to false, you probably just want to drop the decorator. Also, the initial step needs to copy the inherited methods in the the child's attributes in order to make sphinx pick them up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment