2016-07-26 10 views
1

Der vorgeschlagene Decorator here kann den Docstring für Methoden erben, aber nicht für Eigenschaften und Getter.Inherit property getter documentation

Ich habe versucht, es naiv zu erweitern, aber es scheint, dass Docstrings von Eigenschaften schreibgeschützt sind. Gibt es eine Möglichkeit, diese zu erben?

import types 

def fix_docs(cls): 
    for name, func in vars(cls).items(): 
     if isinstance(func, (types.FunctionType, property)) and not func.__doc__: 
      print func, 'needs doc' 
      for parent in cls.__bases__: 
       parfunc = getattr(parent, name, None) 
       if parfunc and getattr(parfunc, '__doc__', None): 
        func.__doc__ = parfunc.__doc__ 
        break 
    return cls 


class X(object): 
    """ 
    some doc 
    """ 

    angle = 10 
    """Not too steep.""" 

    def please_implement(self): 
     """ 
     I have a very thorough documentation 
     :return: 
     """ 
     raise NotImplementedError 

    @property 
    def speed(self): 
     """ 
     Current speed in knots/hour. 
     :return: 
     """ 
     return 0 

    @speed.setter 
    def speed(self, value): 
     """ 

     :param value: 
     :return: 
     """ 
     pass 

@fix_docs 
class SpecialX(X): 
    angle = 30 

    def please_implement(self): 
     return True 

    @property 
    def speed(self): 
     return 10 

    @speed.setter 
    def speed(self, value): 
     self.sp = value 



help(X.speed) 
help(X.angle) 
help(SpecialX.speed) 
help(SpecialX.ange) 

Dies wird nur mich

Traceback (most recent call last): 
<function please_implement at 0x036101B0> needs doc 
<property object at 0x035BE930> needs doc 
    File "C:\Program Files (x86)\JetBrains\PyCharm Community Edition 2016.2\helpers\pydev\pydevd.py", line 1556, in <module> 
    globals = debugger.run(setup['file'], None, None, is_module) 
    File "C:\Program Files (x86)\JetBrains\PyCharm Community Edition 2016.2\helpers\pydev\pydevd.py", line 940, in run 
    pydev_imports.execfile(file, globals, locals) # execute the script 
    File "C:/Users/RedX/.PyCharm2016.2/config/scratches/scratch.py", line 48, in <module> 
    class SpecialX(X): 
    File "C:/Users/RedX/.PyCharm2016.2/config/scratches/scratch.py", line 10, in fix_docs 
    func.__doc__ = parfunc.__doc__ 
TypeError: readonly attribute 

Antwort

0

Ja, Eigentum Docstrings sind schreibgeschützt. Sie müssten eine neue Eigenschaft erstellen:

replacement = property(fget=original.fget, 
         fset=original.fset, 
         fdel=original.fdel, 
         __doc__=parentprop.__doc__) 

und ersetzen Sie das Original damit.

Es könnte etwas besser sein, die ursprüngliche Funktion des docstring zu ersetzen und dann die Eigenschaft regenerieren automatisch, dass durchlaufen:

original.fget.__doc__ = parentprop.__doc__ 
replacement = property(fget=original.fget, 
         fset=original.fset, 
         fdel=original.fdel) 
+0

Können Sie einen Blick auf meinen Vorschlag in meiner Antwort bitte? – RedX

+0

@RedX: Vielleicht möchten Sie nach dem Ersetzen der Eigenschaft "brechen", aber ansonsten sieht es anständig aus. – user2357112

0

Diese Version unter Verwendung __mro__ Mehrfachvererbung und Kopieren der Dokumentation von einer Basis-Base unterstützt stattdessen von __bases__.

def fix_docs(cls): 
    """ 
    This will copy all the missing documentation for methods from the parent classes. 

    :param type cls: class to fix up. 
    :return type: the fixed class. 
    """ 
    for name, func in vars(cls).items(): 
     if isinstance(func, types.FunctionType) and not func.__doc__: 
      for parent in cls.__bases__: 
       parfunc = getattr(parent, name, None) 
       if parfunc and getattr(parfunc, '__doc__', None): 
        func.__doc__ = parfunc.__doc__ 
        break 
     elif isinstance(func, property) and not func.fget.__doc__: 
      for parent in cls.__bases__: 
       parprop = getattr(parent, name, None) 
       if parprop and getattr(parprop.fget, '__doc__', None): 
        newprop = property(fget=func.fget, 
             fset=func.fset, 
             fdel=func.fdel, 
             parprop.fget.__doc__) 
        setattr(cls, name, newprop) 
        break 

    return cls 

Tests:

import pytest 


class X(object): 

    def please_implement(self): 
     """ 
     I have a very thorough documentation 
     :return: 
     """ 
     raise NotImplementedError 

    @property 
    def speed(self): 
     """ 
     Current speed in knots/hour. 
     :return: 
     """ 
     return 0 

    @speed.setter 
    def speed(self, value): 
     """ 

     :param value: 
     :return: 
     """ 
     pass 


class SpecialX(X): 

    def please_implement(self): 
     return True 

    @property 
    def speed(self): 
     return 10 

    @speed.setter 
    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 

    @property 
    def speed(self): 
     return 10 

    @speed.setter 
    def speed(self, value): 
     self.sp = value 


def test_class_does_not_inhirit_works(): 
    fix_docs(X) 


@pytest.mark.parametrize('clazz', [ 
    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 
     """