Last active
December 10, 2019 12:42
-
-
Save a-recknagel/de864922bd4183cf523a2463a2da5f3d to your computer and use it in GitHub Desktop.
inherit docs from superclasses via decorator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.