This is a variation on Paul McGuire’s DocStringInheritor metaclass.
- It inherits a parent member’s docstring if the child member’s docstring is empty.
- It inherits a parent class docstring if the child class docstring is empty.
- It can inherit the docstring from any class in any of the base classes’s MROs, just like regular attribute inheritance.
- Unlike with a class decorator, the metaclass is inherited, so you only need to set the metaclass once in some top-level base class, and docstring inheritance will occur throughout your OOP hierarchy.
1 | import unittest |
This version supports multiple inheritance and copying the documentation from a base’s base by using mro instead of bases.
1 | def fix_docs(cls): |
Test:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126import pytest
class X(object):
def please_implement(self):
"""
I have a very thorough documentation
:return:
"""
raise NotImplementedError
def speed(self):
"""
Current speed in knots/hour.
:return:
"""
return 0
def speed(self, value):
"""
:param value:
:return:
"""
pass
class SpecialX(X):
def please_implement(self):
return True
def speed(self):
return 10
def speed(self, value):
self.sp = value
class VerySpecial(X):
def speed(self):
"""
The fastest speed in knots/hour.
:return: 100
"""
return 100
def please_implement(self):
"""
I have my own words!
:return bool: Always false.
"""
return False
def not_inherited(self):
"""
Look at all these words!
:return:
"""
class A(object):
def please_implement(self):
"""
This doc is not used because X is resolved first in the MRO.
:return:
"""
pass
class B(A):
pass
class HasNoWords(SpecialX, B):
def please_implement(self):
return True
def speed(self):
return 10
def speed(self, value):
self.sp = value
def test_class_does_not_inhirit_works():
fix_docs(X)
SpecialX,
HasNoWords
])
def test_property_and_method_inherit(clazz):
x = fix_docs(clazz)
assert x.please_implement.__doc__ == """
I have a very thorough documentation
:return:
"""
assert x.speed.__doc__ == """
Current speed in knots/hour.
:return:
"""
def test_inherited_class_with_own_doc_is_not_overwritten():
x = fix_docs(VerySpecial)
assert x.please_implement.__doc__ == """
I have my own words!
:return bool: Always false.
"""
assert x.speed.__doc__ == """
The fastest speed in knots/hour.
:return: 100
"""