浏览代码

pygrass: Fix generated documentation for decorated __doc__ methods, for more details about the problem look: https://bitbucket.org/birkenfeld/sphinx/issue/1273/error-when-__doc__-is-a-property, thanks to Luca.

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@61114 15284696-431f-4ddb-bdfa-cd5b030d7da7
Pietro Zambelli 10 年之前
父节点
当前提交
b24d7d3ec9

+ 57 - 0
lib/python/pygrass/functions.py

@@ -332,3 +332,60 @@ def table_exist(cursor, table_name):
             return False
             return False
     one = cursor.fetchone() if cursor else None
     one = cursor.fetchone() if cursor else None
     return True if one and one[0] else False
     return True if one and one[0] else False
+
+
+def docstring_property(class_doc):
+    """Property attribute for docstrings.
+    Took from: https://gist.github.com/bfroehle/4041015
+
+    Usage
+    -----
+
+    >>> class A(object):
+    ...     '''Main docstring'''
+    ...     def __init__(self, x):
+    ...         self.x = x
+    ...     @docstring_property(__doc__)
+    ...     def __doc__(self):
+    ...         return "My value of x is %s." % self.x
+
+    >>> A.__doc__
+    'Main docstring'
+
+    >>> a = A(10)
+    >>> a.__doc__
+    'My value of x is 10.'
+    """
+    def wrapper(fget):
+        return DocstringProperty(class_doc, fget)
+    return wrapper
+
+
+class DocstringProperty(object):
+    """Property for the `__doc__` attribute.
+
+    Different than `property` in the following two ways:
+
+    * When the attribute is accessed from the main class, it returns the value
+      of `class_doc`, *not* the property itself. This is necessary so Sphinx
+      and other documentation tools can access the class docstring.
+
+    * Only supports getting the attribute; setting and deleting raise an
+      `AttributeError`.
+    """
+
+    def __init__(self, class_doc, fget):
+        self.class_doc = class_doc
+        self.fget = fget
+
+    def __get__(self, obj, type=None):
+        if obj is None:
+            return self.class_doc
+        else:
+            return self.fget(obj)
+
+    def __set__(self, obj, value):
+        raise AttributeError("can't set attribute")
+
+    def __delete__(self, obj):
+        raise AttributeError("can't delete attribute")

+ 2 - 1
lib/python/pygrass/modules/interface/flag.py

@@ -6,6 +6,7 @@ Created on Tue Apr  2 18:39:21 2013
 """
 """
 from __future__ import (nested_scopes, generators, division, absolute_import,
 from __future__ import (nested_scopes, generators, division, absolute_import,
                         with_statement, print_function, unicode_literals)
                         with_statement, print_function, unicode_literals)
+from grass.pygrass.functions import docstring_property
 from grass.pygrass.modules.interface import read
 from grass.pygrass.modules.interface import read
 
 
 # TODO add documentation
 # TODO add documentation
@@ -50,7 +51,7 @@ class Flag(object):
     def __repr__(self):
     def __repr__(self):
         return "Flag <%s> (%s)" % (self.name, self.description)
         return "Flag <%s> (%s)" % (self.name, self.description)
 
 
-    @property
+    @docstring_property(__doc__)
     def __doc__(self):
     def __doc__(self):
         """
         """
         {name}: {default}
         {name}: {default}

+ 5 - 4
lib/python/pygrass/modules/interface/module.py

@@ -139,6 +139,7 @@ import time
 
 
 from grass.script.core import Popen, PIPE
 from grass.script.core import Popen, PIPE
 from grass.pygrass.errors import GrassError, ParameterError
 from grass.pygrass.errors import GrassError, ParameterError
+from grass.pygrass.functions import docstring_property
 from grass.pygrass.modules.interface.parameter import Parameter
 from grass.pygrass.modules.interface.parameter import Parameter
 from grass.pygrass.modules.interface.flag import Flag
 from grass.pygrass.modules.interface.flag import Flag
 from grass.pygrass.modules.interface.typedict import TypeDict
 from grass.pygrass.modules.interface.typedict import TypeDict
@@ -244,7 +245,7 @@ class ParallelModuleQueue(object):
 
 
         :param max_num_procs: The maximum number of Module processes that
         :param max_num_procs: The maximum number of Module processes that
                               can be run in parallel
                               can be run in parallel
-        :type max_num_procs: int   
+        :type max_num_procs: int
         """
         """
         self._num_procs = int(max_num_procs)
         self._num_procs = int(max_num_procs)
         self.wait()
         self.wait()
@@ -492,7 +493,7 @@ class Module(object):
     def __repr__(self):
     def __repr__(self):
         return "Module(%r)" % self.name
         return "Module(%r)" % self.name
 
 
-    @property
+    @docstring_property(__doc__)
     def __doc__(self):
     def __doc__(self):
         """{cmd_name}({cmd_params})
         """{cmd_name}({cmd_params})
         """
         """
@@ -547,7 +548,7 @@ class Module(object):
 
 
         This function will wait for the process to terminate in case
         This function will wait for the process to terminate in case
         finish_==True and sets up stdout and stderr. If finish_==False this
         finish_==True and sets up stdout and stderr. If finish_==False this
-        function will return after starting the process. Use 
+        function will return after starting the process. Use
         self.popen.communicate() of self.popen.wait() to wait for the process
         self.popen.communicate() of self.popen.wait() to wait for the process
         termination. The handling of stdout and stderr must then be done
         termination. The handling of stdout and stderr must then be done
         outside of this function.
         outside of this function.
@@ -555,7 +556,7 @@ class Module(object):
         if self.inputs['stdin'].value:
         if self.inputs['stdin'].value:
             self.stdin = self.inputs['stdin'].value
             self.stdin = self.inputs['stdin'].value
             self.stdin_ = PIPE
             self.stdin_ = PIPE
-        
+
         cmd = self.make_cmd()
         cmd = self.make_cmd()
         start = time.time()
         start = time.time()
         self.popen = Popen(cmd,
         self.popen = Popen(cmd,

+ 2 - 4
lib/python/pygrass/modules/interface/parameter.py

@@ -8,7 +8,7 @@ from __future__ import (nested_scopes, generators, division, absolute_import,
                         with_statement, print_function, unicode_literals)
                         with_statement, print_function, unicode_literals)
 import re
 import re
 
 
-
+from grass.pygrass.functions import docstring_property
 from grass.pygrass.modules.interface.read import GETTYPE, element2dict, DOC
 from grass.pygrass.modules.interface.read import GETTYPE, element2dict, DOC
 
 
 
 
@@ -163,9 +163,7 @@ class Parameter(object):
                            'raster', 'vector') else self.typedesc,
                            'raster', 'vector') else self.typedesc,
                            "yes" if self.multiple else "no")
                            "yes" if self.multiple else "no")
 
 
-    # here we use property with a decorator, in this way we mask a method as
-    # a class attribute
-    @property
+    @docstring_property(__doc__)
     def __doc__(self):
     def __doc__(self):
         """Return the docstring of the parameter
         """Return the docstring of the parameter
 
 

+ 3 - 1
lib/python/pygrass/modules/interface/typedict.py

@@ -12,6 +12,8 @@ try:
 except ImportError:
 except ImportError:
     from grass.pygrass.orderdict import OrderedDict
     from grass.pygrass.orderdict import OrderedDict
 
 
+from grass.pygrass.functions import docstring_property
+
 
 
 class TypeDict(OrderedDict):
 class TypeDict(OrderedDict):
     def __init__(self, dict_type, *args, **kargs):
     def __init__(self, dict_type, *args, **kargs):
@@ -39,7 +41,7 @@ class TypeDict(OrderedDict):
             str_err = 'The value: %r is not a %s instance.'
             str_err = 'The value: %r is not a %s instance.'
             raise TypeError(str_err % (value, self._type.__name__))
             raise TypeError(str_err % (value, self._type.__name__))
 
 
-    @property
+    @docstring_property(__doc__)
     def __doc__(self):
     def __doc__(self):
         return '\n'.join([self.__getitem__(obj).__doc__
         return '\n'.join([self.__getitem__(obj).__doc__
                           for obj in self.__iter__()])
                           for obj in self.__iter__()])