Il s'agit d'une variante de La métaclasse DocStringInheritor de Paul McGuire .
- Il hérite de la docstring d'un membre parent si la docstring du membre enfant est vide. du membre enfant est vide.
- Elle hérite de la docstring d'une classe parent si la docstring de la classe enfant est vide.
- Elle peut hériter de la docstring de n'importe quelle classe dans n'importe quelle MRO de la classe de base, tout comme l'héritage d'un attribut ordinaire.
- Contrairement à un décorateur de classe, la métaclasse est héritée, de sorte que vous ne devez définir la métaclasse qu'une seule fois dans une classe de base de haut niveau, et l'héritage de la docstring se produira tout au long de votre hiérarchie OOP.
import unittest
import sys
class DocStringInheritor(type):
"""
A variation on
http://groups.google.com/group/comp.lang.python/msg/26f7b4fcb4d66c95
by Paul McGuire
"""
def __new__(meta, name, bases, clsdict):
if not('__doc__' in clsdict and clsdict['__doc__']):
for mro_cls in (mro_cls for base in bases for mro_cls in base.mro()):
doc=mro_cls.__doc__
if doc:
clsdict['__doc__']=doc
break
for attr, attribute in clsdict.items():
if not attribute.__doc__:
for mro_cls in (mro_cls for base in bases for mro_cls in base.mro()
if hasattr(mro_cls, attr)):
doc=getattr(getattr(mro_cls,attr),'__doc__')
if doc:
if isinstance(attribute, property):
clsdict[attr] = property(attribute.fget, attribute.fset,
attribute.fdel, doc)
else:
attribute.__doc__ = doc
break
return type.__new__(meta, name, bases, clsdict)
class Test(unittest.TestCase):
def test_null(self):
class Foo(object):
def frobnicate(self): pass
class Bar(Foo, metaclass=DocStringInheritor):
pass
self.assertEqual(Bar.__doc__, object.__doc__)
self.assertEqual(Bar().__doc__, object.__doc__)
self.assertEqual(Bar.frobnicate.__doc__, None)
def test_inherit_from_parent(self):
class Foo(object):
'Foo'
def frobnicate(self):
'Frobnicate this gonk.'
class Bar(Foo, metaclass=DocStringInheritor):
pass
self.assertEqual(Foo.__doc__, 'Foo')
self.assertEqual(Foo().__doc__, 'Foo')
self.assertEqual(Bar.__doc__, 'Foo')
self.assertEqual(Bar().__doc__, 'Foo')
self.assertEqual(Bar.frobnicate.__doc__, 'Frobnicate this gonk.')
def test_inherit_from_mro(self):
class Foo(object):
'Foo'
def frobnicate(self):
'Frobnicate this gonk.'
class Bar(Foo):
pass
class Baz(Bar, metaclass=DocStringInheritor):
pass
self.assertEqual(Baz.__doc__, 'Foo')
self.assertEqual(Baz().__doc__, 'Foo')
self.assertEqual(Baz.frobnicate.__doc__, 'Frobnicate this gonk.')
def test_inherit_metaclass_(self):
class Foo(object):
'Foo'
def frobnicate(self):
'Frobnicate this gonk.'
class Bar(Foo, metaclass=DocStringInheritor):
pass
class Baz(Bar):
pass
self.assertEqual(Baz.__doc__, 'Foo')
self.assertEqual(Baz().__doc__, 'Foo')
self.assertEqual(Baz.frobnicate.__doc__, 'Frobnicate this gonk.')
def test_property(self):
class Foo(object):
@property
def frobnicate(self):
'Frobnicate this gonk.'
class Bar(Foo, metaclass=DocStringInheritor):
@property
def frobnicate(self): pass
self.assertEqual(Bar.frobnicate.__doc__, 'Frobnicate this gonk.')
if __name__ == '__main__':
sys.argv.insert(1, '--verbose')
unittest.main(argv=sys.argv)