From 7f1a8a947d9629d956157464814541dbb764defb Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 22 Jan 2010 02:04:25 +0000 Subject: initial sphinx doc generation support for python and C modules. python modules bpy.app, bpy.utils are now included in docs. C defined python module bpy.props has its docstrings extracted and written directly into sphinx docs since the C methods cant be inspected. added docstrings to bpy.props and improved some in bpy.utils. will update online docs tomorrow. --- source/blender/python/intern/bpy_props.c | 60 +++++++++++-- source/blender/python/sphinx_doc_gen.py | 147 +++++++++++++++++++++++++++---- 2 files changed, 180 insertions(+), 27 deletions(-) (limited to 'source') diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 938aaca4b9a..946e94c7064 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -46,6 +46,10 @@ static PyObject *bpy_prop_deferred_return(void *func, PyObject *kw) /* Function that sets RNA, NOTE - self is NULL when called from python, but being abused from C so we can pass the srna allong * This isnt incorrect since its a python object - but be careful */ +static char BPy_BoolProperty_doc[] = +".. function:: BoolProperty(name=\"\", description=\"\", default=False, hidden=False)\n" +"\n" +" Returns a new boolean property definition.."; PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) { @@ -79,6 +83,10 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) } } +static char BPy_IntProperty_doc[] = +".. function:: IntProperty(name=\"\", description=\"\", default=0, min=-sys.maxint, max=sys.maxint, soft_min=-sys.maxint, soft_max=sys.maxint, step=1, hidden=False)\n" +"\n" +" Returns a new int property definition."; PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -113,6 +121,10 @@ PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) } } +static char BPy_FloatProperty_doc[] = +".. function:: FloatProperty(name=\"\", description=\"\", default=0.0, min=sys.float_info.min, max=sys.float_info.max, soft_min=sys.float_info.min, soft_max=sys.float_info.max, step=3, precision=2, hidden=False)\n" +"\n" +" Returns a new float property definition."; PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -147,6 +159,10 @@ PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) } } +static char BPy_FloatVectorProperty_doc[] = +".. function:: FloatVectorProperty(name=\"\", description=\"\", default=(0.0, 0.0, 0.0), min=sys.float_info.min, max=sys.float_info.max, soft_min=sys.float_info.min, soft_max=sys.float_info.max, step=3, precision=2, hidden=False, size=3)\n" +"\n" +" Returns a new vector float property definition."; PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -213,6 +229,10 @@ PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw) } } +static char BPy_StringProperty_doc[] = +".. function:: StringProperty(name=\"\", description=\"\", default=\"\", maxlen=0, hidden=False)\n" +"\n" +" Returns a new string property definition."; PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -291,6 +311,13 @@ static EnumPropertyItem *enum_items_from_py(PyObject *value, const char *def, in return items; } +static char BPy_EnumProperty_doc[] = +".. function:: EnumProperty(items, name=\"\", description=\"\", default=\"\", hidden=False)\n" +"\n" +" Returns a new enumerator property definition.\n" +"\n" +" :arg items: The items that make up this enumerator.\n" +" :type items: sequence of string triplets"; PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -349,6 +376,13 @@ static StructRNA *pointer_type_from_py(PyObject *value) return srna; } +static char BPy_PointerProperty_doc[] = +".. function:: PointerProperty(items, type=\"\", description=\"\", default=\"\", hidden=False)\n" +"\n" +" Returns a new pointer property definition.\n" +"\n" +" :arg type: Dynamic type from :mod:`bpy.types`.\n" +" :type type: class"; PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -388,6 +422,13 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) return NULL; } +static char BPy_CollectionProperty_doc[] = +".. function:: CollectionProperty(items, type=\"\", description=\"\", default=\"\", hidden=False)\n" +"\n" +" Returns a new collection property definition.\n" +"\n" +" :arg type: Dynamic type from :mod:`bpy.types`.\n" +" :type type: class"; PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) { StructRNA *srna; @@ -428,21 +469,22 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) } static struct PyMethodDef props_methods[] = { - {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"FloatVectorProperty", (PyCFunction)BPy_FloatVectorProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"EnumProperty", (PyCFunction)BPy_EnumProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"PointerProperty", (PyCFunction)BPy_PointerProperty, METH_VARARGS|METH_KEYWORDS, ""}, - {"CollectionProperty", (PyCFunction)BPy_CollectionProperty, METH_VARARGS|METH_KEYWORDS, ""}, + {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, BPy_BoolProperty_doc}, + {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, BPy_IntProperty_doc}, + {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, BPy_FloatProperty_doc}, + {"FloatVectorProperty", (PyCFunction)BPy_FloatVectorProperty, METH_VARARGS|METH_KEYWORDS, BPy_FloatVectorProperty_doc}, + {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, BPy_StringProperty_doc}, + {"EnumProperty", (PyCFunction)BPy_EnumProperty, METH_VARARGS|METH_KEYWORDS, BPy_EnumProperty_doc}, + {"PointerProperty", (PyCFunction)BPy_PointerProperty, METH_VARARGS|METH_KEYWORDS, BPy_PointerProperty_doc}, + {"CollectionProperty", (PyCFunction)BPy_CollectionProperty, METH_VARARGS|METH_KEYWORDS, BPy_CollectionProperty_doc}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef props_module = { PyModuleDef_HEAD_INIT, "bpy.props", - "", + "This module defines properties to extend blenders internal data, the result of these functions" + " is used to assign properties to classes registered with blender and can't be used directly.", -1,/* multiple "initialization" just copies the module dict. */ props_methods, NULL, NULL, NULL, NULL diff --git a/source/blender/python/sphinx_doc_gen.py b/source/blender/python/sphinx_doc_gen.py index ec17139b843..a882e145aec 100644 --- a/source/blender/python/sphinx_doc_gen.py +++ b/source/blender/python/sphinx_doc_gen.py @@ -49,6 +49,114 @@ def write_indented_lines(ident, fn, text): for l in text.split("\n"): fn(ident + l.strip() + "\n") + +def pymethod2sphinx(ident, fw, identifier, py_func): + ''' + class method to sphinx + ''' + arg_str = inspect.formatargspec(*inspect.getargspec(py_func)) + if arg_str.startswith("(self, "): + arg_str = "(" + arg_str[7:] + func_type = "method" + elif arg_str.startswith("(cls, "): + arg_str = "(" + arg_str[6:] + func_type = "classmethod" + else: + func_type = "staticmethod" + + fw(ident + ".. %s:: %s%s\n\n" % (func_type, identifier, arg_str)) + if py_func.__doc__: + write_indented_lines(ident + " ", fw, py_func.__doc__) + fw("\n") + + +def pyfunc2sphinx(ident, fw, identifier, py_func, is_class=True): + ''' + function or class method to sphinx + ''' + arg_str = inspect.formatargspec(*inspect.getargspec(py_func)) + + if not is_class: + func_type = "function" + + # ther rest are class methods + elif arg_str.startswith("(self, "): + arg_str = "(" + arg_str[7:] + func_type = "method" + elif arg_str.startswith("(cls, "): + arg_str = "(" + arg_str[6:] + func_type = "classmethod" + else: + func_type = "staticmethod" + + fw(ident + ".. %s:: %s%s\n\n" % (func_type, identifier, arg_str)) + if py_func.__doc__: + write_indented_lines(ident + " ", fw, py_func.__doc__.strip()) + fw("\n") + +def py_c_func2sphinx(ident, fw, identifier, py_func, is_class=True): + ''' + c defined function to sphinx. + ''' + + # dump the docstring, assume its formatted correctly + if py_func.__doc__: + for l in py_func.__doc__.split("\n"): + fw(ident + l + "\n") + fw("\n") + else: + fw(ident + ".. function:: %s()\n\n" % identifier) + fw(ident + " Undocumented function.\n\n" % identifier) + + +def pyprop2sphinx(ident, fw, identifier, py_prop): + ''' + python property to sphinx + ''' + fw(ident + ".. attribute:: %s\n\n" % identifier) + write_indented_lines(ident + " ", fw, py_prop.__doc__) + if py_prop.fset is None: + fw(ident + " (readonly)\n\n") + + +def pymodule2sphinx(BASEPATH, module_name, module, title): + import types + + filepath = os.path.join(BASEPATH, module_name + ".rst") + + file = open(filepath, "w") + print(filepath) + print(filepath) + fw = file.write + + fw(title + "\n") + fw(("=" * len(title)) + "\n\n") + + fw(".. module:: %s\n\n" % module_name) + + if module.__doc__: + # Note, may contain sphinx syntax, dont mangle! + fw(module.__doc__.strip()) + fw("\n\n") + + for attribute in dir(module): + if not attribute.startswith("_"): + value = getattr(module, attribute) + + value_type = type(value) + print(attribute, value_type) + if value_type == types.FunctionType: + pyfunc2sphinx("", fw, attribute, value, is_class=False) + elif value_type in (types.BuiltinMethodType, types.BuiltinFunctionType): # both the same at the moment but to be future proof + # note: can't get args from these, so dump the string as is + # this means any module used like this must have fully formatted docstrings. + py_c_func2sphinx("", fw, attribute, value, is_class=False) + + # TODO, more types... + + file.close() + + def rna2sphinx(BASEPATH): structs, funcs, ops, props = rna_info.BuildRNAInfo() @@ -80,8 +188,27 @@ def rna2sphinx(BASEPATH): fw(" :glob:\n\n") fw(" bpy.ops.*\n\n") fw(" bpy.types.*\n\n") + + # py modules + fw(" bpy.utils\n\n") + fw(" bpy.app\n\n") + + # C modules + fw(" bpy.props\n\n") + file.close() + # python modules + from bpy import utils as module + pymodule2sphinx(BASEPATH, "bpy.utils", module, "Blender Python Utilities") + from bpy import app as module + pymodule2sphinx(BASEPATH, "bpy.app", module, "Blender Python Application Constants") + + from bpy import props as module + pymodule2sphinx(BASEPATH, "bpy.props", module, "Blender Python Property Definitions") + del module + + if 0: filepath = os.path.join(BASEPATH, "bpy.rst") file = open(filepath, "w") @@ -167,10 +294,7 @@ def rna2sphinx(BASEPATH): py_properties = struct.get_py_properties() py_prop = None for identifier, py_prop in py_properties: - fw(" .. attribute:: %s\n\n" % identifier) - write_indented_lines(" ", fw, py_prop.__doc__) - if py_prop.fset is None: - fw(" (readonly)\n\n") + pyprop2sphinx(" ", fw, identifier, py_prop) del py_properties, py_prop for func in struct.functions: @@ -201,20 +325,7 @@ def rna2sphinx(BASEPATH): py_func = None for identifier, py_func in py_funcs: - arg_str = inspect.formatargspec(*inspect.getargspec(py_func)) - if arg_str.startswith("(self, "): - arg_str = "(" + arg_str[7:] - func_type = "method" - elif arg_str.startswith("(cls, "): - arg_str = "(" + arg_str[6:] - func_type = "classmethod" - else: - func_type = "staticmethod" - - fw(" .. %s:: %s%s\n\n" % (func_type, identifier, arg_str)) - if py_func.__doc__: - write_indented_lines(" ", fw, py_func.__doc__) - fw("\n") + pyfunc2sphinx(" ", fw, identifier, py_func, is_class=True) del py_funcs, py_func if struct.references: -- cgit v1.2.3