863 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			863 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|  # ***** BEGIN GPL LICENSE BLOCK *****
 | |
|  #
 | |
|  # This program is free software; you can redistribute it and/or
 | |
|  # modify it under the terms of the GNU General Public License
 | |
|  # as published by the Free Software Foundation; either version 2
 | |
|  # of the License, or (at your option) any later version.
 | |
|  #
 | |
|  # This program is distributed in the hope that it will be useful,
 | |
|  # but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  # GNU General Public License for more details.
 | |
|  #
 | |
|  # You should have received a copy of the GNU General Public License
 | |
|  # along with this program; if not, write to the Free Software Foundation,
 | |
|  # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | |
|  #
 | |
|  # Contributor(s): Campbell Barton
 | |
|  #
 | |
|  # #**** END GPL LICENSE BLOCK #****
 | |
| 
 | |
| script_help_msg = '''
 | |
| Usage,
 | |
| run this script from blenders root path once you have compiled blender
 | |
|     ./blender.bin -b -P /b/source/blender/python/doc/sphinx_doc_gen.py
 | |
| 
 | |
| This will generate python files in "./source/blender/python/doc/sphinx-in"
 | |
| Generate html docs by running...
 | |
|     
 | |
|     sphinx-build source/blender/python/doc/sphinx-in source/blender/python/doc/sphinx-out
 | |
| 
 | |
| 
 | |
| For PDF generation
 | |
| 
 | |
|     sphinx-build -b latex source/blender/python/doc/sphinx-in source/blender/python/doc/sphinx-out
 | |
|     cd source/blender/python/doc/sphinx-out
 | |
|     make
 | |
| '''
 | |
| 
 | |
| # import rpdb2; rpdb2.start_embedded_debugger('test')
 | |
| 
 | |
| import os
 | |
| import inspect
 | |
| import bpy
 | |
| import rna_info
 | |
| reload(rna_info)
 | |
| 
 | |
| # lame, python wont give some access
 | |
| ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
 | |
| MethodDescriptorType = type(dict.get)
 | |
| GetSetDescriptorType = type(int.real)
 | |
| 
 | |
| EXAMPLE_SET = set()
 | |
| EXAMPLE_SET_USED = set()
 | |
| 
 | |
| _BPY_STRUCT_FAKE = "bpy_struct"
 | |
| _BPY_FULL_REBUILD = False
 | |
| 
 | |
| def undocumented_message(module_name, type_name, identifier):
 | |
|     message = "Undocumented (`contribute " \
 | |
|         "<http://wiki.blender.org/index.php/Dev:2.5/Py/API/Documentation/Contribute" \
 | |
|         "?action=edit§ion=new&preload=Dev:2.5/Py/API/Documentation/Contribute/Howto-message" \
 | |
|         "&preloadtitle=%s.%s.%s>`_)\n\n" % (module_name, type_name, identifier)
 | |
|     return message
 | |
| 
 | |
| 
 | |
| def range_str(val):
 | |
|     '''
 | |
|     Converts values to strings for the range directive.
 | |
|     (unused function it seems)
 | |
|     '''
 | |
|     if val < -10000000:	return '-inf'
 | |
|     if val >  10000000:	return 'inf'
 | |
|     if type(val)==float:
 | |
|         return '%g'  % val
 | |
|     else:
 | |
|         return str(val)
 | |
| 
 | |
| 
 | |
| def write_example_ref(ident, fw, example_id, ext="py"):
 | |
|     if example_id in EXAMPLE_SET:
 | |
|         fw("%s.. literalinclude:: ../examples/%s.%s\n\n" % (ident, example_id, ext))
 | |
|         EXAMPLE_SET_USED.add(example_id)
 | |
|     else:
 | |
|         if bpy.app.debug:
 | |
|             print("\tskipping example:", example_id)
 | |
| 
 | |
| 
 | |
| def write_indented_lines(ident, fn, text, strip=True):
 | |
|     '''
 | |
|     Apply same indentation to all lines in a multilines text.
 | |
|     '''
 | |
|     if text is None:
 | |
|         return
 | |
|     for l in text.split("\n"):
 | |
|         if strip:
 | |
|             fn(ident + l.strip() + "\n")
 | |
|         else:
 | |
|             fn(ident + l + "\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_descr2sphinx(ident, fw, descr, module_name, type_name, identifier):    
 | |
|     if identifier.startswith("_"):
 | |
|         return
 | |
|     
 | |
|     doc = descr.__doc__
 | |
|     if not doc:
 | |
|         doc = undocumented_message(module_name, type_name, identifier)
 | |
|     
 | |
|     if type(descr) == GetSetDescriptorType:
 | |
|         fw(ident + ".. attribute:: %s\n\n" % identifier)
 | |
|         write_indented_lines(ident + "   ", fw, doc, False)
 | |
|     elif type(descr) in (MethodDescriptorType, ClassMethodDescriptorType):
 | |
|         write_indented_lines(ident, fw, doc, False)
 | |
|     else:
 | |
|         raise TypeError("type was not GetSetDescriptorType, MethodDescriptorType or ClassMethodDescriptorType")
 | |
| 
 | |
|     write_example_ref(ident, fw, module_name + "." + type_name + "." + identifier)
 | |
|     fw("\n")
 | |
| 
 | |
| 
 | |
| def py_c_func2sphinx(ident, fw, module_name, type_name, identifier, py_func, is_class=True):
 | |
|     '''
 | |
|     c defined function to sphinx.
 | |
|     '''
 | |
|     
 | |
|     # dump the docstring, assume its formatted correctly
 | |
|     if py_func.__doc__:
 | |
|         write_indented_lines(ident, fw, py_func.__doc__, False)
 | |
|         fw("\n")
 | |
|     else:
 | |
|         fw(ident + ".. function:: %s()\n\n" % identifier)
 | |
|         fw(ident + "   " + undocumented_message(module_name, type_name, identifier))
 | |
| 
 | |
| 
 | |
| def pyprop2sphinx(ident, fw, identifier, py_prop):
 | |
|     '''
 | |
|     python property to sphinx
 | |
|     '''
 | |
|     # readonly properties use "data" directive, variables use "attribute" directive
 | |
|     if py_prop.fset is None:
 | |
|         fw(ident + ".. data:: %s\n\n" % identifier)
 | |
|     else:
 | |
|         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
 | |
|     attribute_set = set()
 | |
|     filepath = os.path.join(BASEPATH, module_name + ".rst")
 | |
|     
 | |
|     file = open(filepath, "w")
 | |
| 
 | |
|     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")
 | |
|         
 | |
|     write_example_ref("", fw, module_name)
 | |
|     
 | |
|     # write members of the module
 | |
|     # only tested with PyStructs which are not exactly modules
 | |
|     for key, descr in sorted(type(module).__dict__.items()):
 | |
|         if type(descr) == types.MemberDescriptorType:
 | |
|             if descr.__doc__:
 | |
|                 fw(".. data:: %s\n\n" % key)
 | |
|                 write_indented_lines("   ", fw, descr.__doc__, False)
 | |
|                 attribute_set.add(key)
 | |
|                 fw("\n")
 | |
|     del key, descr
 | |
|     
 | |
|     classes = []
 | |
| 
 | |
|     for attribute in sorted(dir(module)):
 | |
|         if not attribute.startswith("_"):
 | |
| 
 | |
|             if attribute in attribute_set:
 | |
|                 continue
 | |
| 
 | |
|             if attribute.startswith("n_"): # annoying exception, needed for bpy.app
 | |
|                 continue
 | |
|             
 | |
|             value = getattr(module, attribute)
 | |
| 
 | |
|             value_type = type(value)
 | |
| 
 | |
|             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, module_name, module, attribute, value, is_class=False)
 | |
|             elif value_type == type:
 | |
|                 classes.append((attribute, value))
 | |
|             elif value_type in (bool, int, float, str, tuple):
 | |
|                 # constant, not much fun we can do here except to list it.
 | |
|                 # TODO, figure out some way to document these!
 | |
|                 fw(".. data:: %s\n\n" % attribute)
 | |
|                 write_indented_lines("   ", fw, "constant value %s" % repr(value), False)
 | |
|                 fw("\n")
 | |
|             else:
 | |
|                 print("\tnot documenting %s.%s" % (module_name, attribute))
 | |
|                 continue
 | |
| 
 | |
|             attribute_set.add(attribute)
 | |
|             # TODO, more types...
 | |
| 
 | |
|     # write collected classes now
 | |
|     for (type_name, value) in classes:
 | |
|         # May need to be its own function
 | |
|         fw(".. class:: %s\n\n" % type_name)
 | |
|         if value.__doc__:
 | |
|             write_indented_lines("   ", fw, value.__doc__, False)
 | |
|             fw("\n")
 | |
|         write_example_ref("   ", fw, module_name + "." + type_name)
 | |
| 
 | |
|         descr_items = [(key, descr) for key, descr in sorted(value.__dict__.items()) if not key.startswith("__")]
 | |
| 
 | |
|         for key, descr in descr_items:
 | |
|             if type(descr) == ClassMethodDescriptorType:
 | |
|                 py_descr2sphinx("   ", fw, descr, module_name, type_name, key)
 | |
| 
 | |
|         for key, descr in descr_items:
 | |
|             if type(descr) == MethodDescriptorType:
 | |
|                 py_descr2sphinx("   ", fw, descr, module_name, type_name, key)
 | |
| 
 | |
|         for key, descr in descr_items:
 | |
|             if type(descr) == GetSetDescriptorType:
 | |
|                 py_descr2sphinx("   ", fw, descr, module_name, type_name, key)
 | |
| 
 | |
|         fw("\n\n")
 | |
| 
 | |
|     file.close()
 | |
| 
 | |
| 
 | |
| 
 | |
| def rna2sphinx(BASEPATH):
 | |
| 
 | |
|     structs, funcs, ops, props = rna_info.BuildRNAInfo()
 | |
| 
 | |
|     try:
 | |
|         os.mkdir(BASEPATH)
 | |
|     except:
 | |
|         pass
 | |
| 
 | |
|     # conf.py - empty for now
 | |
|     filepath = os.path.join(BASEPATH, "conf.py")
 | |
|     file = open(filepath, "w")
 | |
|     fw = file.write
 | |
| 
 | |
| 
 | |
|     version_string = bpy.app.version_string.split("(")[0]
 | |
|     if bpy.app.build_revision != "Unknown":
 | |
|         version_string = version_string + " r" + bpy.app.build_revision
 | |
|     
 | |
|     # for use with files
 | |
|     version_string_fp = "_".join(str(v) for v in bpy.app.version)
 | |
|     
 | |
|     fw("project = 'Blender'\n")
 | |
|     # fw("master_doc = 'index'\n")
 | |
|     fw("copyright = u'Blender Foundation'\n")
 | |
|     fw("version = '%s - UNSTABLE API'\n" % version_string)
 | |
|     fw("release = '%s - UNSTABLE API'\n" % version_string)
 | |
|     fw("html_theme = 'blender-org'\n")
 | |
|     fw("html_theme_path = ['../']\n")
 | |
|     fw("html_favicon = 'favicon.ico'\n")
 | |
|     # not helpful since the source us generated, adds to upload size.
 | |
|     fw("html_copy_source = False\n")
 | |
|     fw("\n")
 | |
|     # needed for latex, pdf gen
 | |
|     fw("latex_documents = [ ('contents', 'contents.tex', 'Blender Index', 'Blender Foundation', 'manual'), ]\n")
 | |
|     fw("latex_paper_size = 'a4paper'\n")
 | |
|     file.close()
 | |
| 
 | |
| 
 | |
|     filepath = os.path.join(BASEPATH, "contents.rst")
 | |
|     file = open(filepath, "w")
 | |
|     fw = file.write
 | |
|     
 | |
|     fw("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n")
 | |
|     fw(" Blender Documentation contents\n")
 | |
|     fw("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n")
 | |
|     fw("\n")
 | |
|     fw("This document is an API reference for Blender %s. built %s.\n" % (version_string, bpy.app.build_date))
 | |
|     fw("\n")
 | |
|     fw("An introduction to Blender and Python can be found at <http://wiki.blender.org/index.php/Dev:2.5/Py/API/Intro>\n")
 | |
|     fw("\n")
 | |
|     fw("`A PDF version of this document is also available <blender_python_reference_%s.pdf>`__\n" % version_string_fp)
 | |
|     fw("\n")
 | |
|     fw(".. warning:: The Python API in Blender is **UNSTABLE**, It should only be used for testing, any script written now may break in future releases.\n")
 | |
|     fw("   \n")
 | |
|     fw("   The following areas are subject to change.\n")
 | |
|     fw("      * operator names and arguments\n")
 | |
|     fw("      * render api\n")
 | |
|     fw("      * function calls with the data api (any function calls with values accessed from bpy.data), including functions for importing and exporting meshes\n")
 | |
|     fw("      * class registration (Operator, Panels, Menus, Headers)\n")
 | |
|     fw("      * modules: bpy.props, blf)\n")
 | |
|     fw("      * members in the bpy.context have to be reviewed\n")
 | |
|     fw("      * python defined modal operators, especially drawing callbacks are highly experemental\n")
 | |
|     fw("   \n")
 | |
|     fw("   These parts of the API are relatively stable and are unlikely to change significantly\n")
 | |
|     fw("      * data API, access to attributes of blender data such as mesh verts, material color, timeline frames and scene objects\n")
 | |
|     fw("      * user interface functions for defining buttons, creation of menus, headers, panels\n")
 | |
|     fw("      * modules: bgl, mathutils and geometry\n")
 | |
|     fw("      * game engine modules\n")
 | |
|     fw("\n")
 | |
| 
 | |
|     fw("===================\n")
 | |
|     fw("Application Modules\n")
 | |
|     fw("===================\n")
 | |
|     fw("\n")
 | |
|     fw(".. toctree::\n")
 | |
|     fw("   :maxdepth: 1\n\n")
 | |
|     fw("   bpy.data.rst\n\n") # note: not actually a module
 | |
|     fw("   bpy.ops.rst\n\n")
 | |
|     fw("   bpy.types.rst\n\n")
 | |
|     
 | |
|     # py modules
 | |
|     fw("   bpy.utils.rst\n\n")
 | |
|     fw("   bpy.path.rst\n\n")
 | |
|     fw("   bpy.app.rst\n\n")
 | |
|     
 | |
|     # C modules
 | |
|     fw("   bpy.props.rst\n\n")
 | |
| 
 | |
|     fw("==================\n")
 | |
|     fw("Standalone Modules\n")
 | |
|     fw("==================\n")
 | |
|     fw("\n")
 | |
|     fw(".. toctree::\n")
 | |
|     fw("   :maxdepth: 1\n\n")
 | |
| 
 | |
| 
 | |
|     fw("   mathutils.rst\n\n")
 | |
|     fw("   blf.rst\n\n")
 | |
|     fw("   aud.rst\n\n")
 | |
|     
 | |
|     # game engine
 | |
|     fw("===================\n")
 | |
|     fw("Game Engine Modules\n")
 | |
|     fw("===================\n")
 | |
|     fw("\n")
 | |
|     fw(".. toctree::\n")
 | |
|     fw("   :maxdepth: 1\n\n")
 | |
|     fw("   bge.types.rst\n\n")
 | |
|     fw("   bge.logic.rst\n\n")
 | |
|     fw("   bge.render.rst\n\n")
 | |
|     fw("   bge.events.rst\n\n")
 | |
| 
 | |
|     file.close()
 | |
| 
 | |
| 
 | |
|     # internal modules
 | |
|     filepath = os.path.join(BASEPATH, "bpy.ops.rst")
 | |
|     file = open(filepath, "w")
 | |
|     fw = file.write
 | |
|     fw("Operators (bpy.ops)\n")
 | |
|     fw("===================\n\n")
 | |
|     fw(".. toctree::\n")
 | |
|     fw("   :glob:\n\n")
 | |
|     fw("   bpy.ops.*\n\n")
 | |
|     file.close()
 | |
| 
 | |
|     filepath = os.path.join(BASEPATH, "bpy.types.rst")
 | |
|     file = open(filepath, "w")
 | |
|     fw = file.write
 | |
|     fw("Types (bpy.types)\n")
 | |
|     fw("=================\n\n")
 | |
|     fw(".. toctree::\n")
 | |
|     fw("   :glob:\n\n")
 | |
|     fw("   bpy.types.*\n\n")
 | |
|     file.close()
 | |
| 
 | |
| 
 | |
|     # not actually a module, only write this file so we
 | |
|     # can reference in the TOC
 | |
|     filepath = os.path.join(BASEPATH, "bpy.data.rst")
 | |
|     file = open(filepath, "w")
 | |
|     fw = file.write
 | |
|     fw("Data Access (bpy.data)\n")
 | |
|     fw("======================\n\n")
 | |
|     fw(".. module:: bpy\n")
 | |
|     fw("\n")
 | |
|     fw("This module is used for all blender/python access.\n")
 | |
|     fw("\n")
 | |
|     fw(".. literalinclude:: ../examples/bpy.data.py\n")
 | |
|     fw("\n")
 | |
|     fw(".. data:: data\n")
 | |
|     fw("\n")
 | |
|     fw("   Access to blenders internal data\n")
 | |
|     fw("\n")
 | |
|     fw("   :type: :class:`bpy.types.BlendData`\n")
 | |
|     file.close()
 | |
| 
 | |
|     EXAMPLE_SET_USED.add("bpy.data")
 | |
| 
 | |
| 
 | |
|     # python modules
 | |
|     from bpy import utils as module
 | |
|     pymodule2sphinx(BASEPATH, "bpy.utils", module, "Utilities (bpy.utils)")
 | |
| 
 | |
|     from bpy import path as module
 | |
|     pymodule2sphinx(BASEPATH, "bpy.path", module, "Path Utilities (bpy.path)")
 | |
| 
 | |
|     # C modules
 | |
|     from bpy import app as module
 | |
|     pymodule2sphinx(BASEPATH, "bpy.app", module, "Application Data (bpy.app)")
 | |
| 
 | |
|     from bpy import props as module
 | |
|     pymodule2sphinx(BASEPATH, "bpy.props", module, "Property Definitions (bpy.props)")
 | |
|     
 | |
|     import mathutils as module
 | |
|     pymodule2sphinx(BASEPATH, "mathutils", module, "Math Types & Utilities (mathutils)")
 | |
|     del module
 | |
| 
 | |
|     import blf as module
 | |
|     pymodule2sphinx(BASEPATH, "blf", module, "Font Drawing (blf)")
 | |
|     del module
 | |
|     
 | |
|     import aud as module
 | |
|     pymodule2sphinx(BASEPATH, "aud", module, "Audio System (aud)")
 | |
|     del module
 | |
| 
 | |
|     # game engine
 | |
|     import shutil
 | |
|     # copy2 keeps time/date stamps
 | |
|     shutil.copy2(os.path.join(BASEPATH, "../../../../gameengine/PyDoc/bge.types.rst"), BASEPATH)
 | |
|     shutil.copy2(os.path.join(BASEPATH, "../../../../gameengine/PyDoc/bge.logic.rst"), BASEPATH)
 | |
|     shutil.copy2(os.path.join(BASEPATH, "../../../../gameengine/PyDoc/bge.render.rst"), BASEPATH)
 | |
|     shutil.copy2(os.path.join(BASEPATH, "../../../../gameengine/PyDoc/bge.events.rst"), BASEPATH)
 | |
| 
 | |
| 
 | |
|     if 0:
 | |
|         filepath = os.path.join(BASEPATH, "bpy.rst")
 | |
|         file = open(filepath, "w")
 | |
|         fw = file.write
 | |
|         
 | |
|         fw("\n")
 | |
| 
 | |
|         title = ":mod:`bpy` --- Blender Python Module"
 | |
|         fw("%s\n%s\n\n" % (title, "=" * len(title)))
 | |
|         fw(".. module:: bpy.types\n\n")
 | |
|         file.close()
 | |
| 
 | |
|     def write_param(ident, fw, prop, is_return=False):
 | |
|         if is_return:
 | |
|             id_name = "return"
 | |
|             id_type = "rtype"
 | |
|             kwargs = {"as_ret": True, "class_fmt": ":class:`%s`"}
 | |
|             identifier = ""
 | |
|         else:
 | |
|             id_name = "arg"
 | |
|             id_type = "type"
 | |
|             kwargs = {"as_arg": True, "class_fmt": ":class:`%s`"}
 | |
|             identifier = " %s" % prop.identifier
 | |
| 
 | |
|         type_descr = prop.get_type_description(**kwargs)
 | |
|         if prop.name or prop.description:
 | |
|             fw(ident + ":%s%s: %s\n" % (id_name, identifier, ", ".join(val for val in (prop.name, prop.description) if val)))
 | |
|         fw(ident + ":%s%s: %s\n" % (id_type, identifier, type_descr))
 | |
| 
 | |
|     def write_struct(struct):
 | |
|         #if not struct.identifier.startswith("Sc") and not struct.identifier.startswith("I"):
 | |
|         #    return
 | |
| 
 | |
|         #if not struct.identifier == "Object":
 | |
|         #    return
 | |
| 
 | |
|         filepath = os.path.join(BASEPATH, "bpy.types.%s.rst" % struct.identifier)
 | |
|         file = open(filepath, "w")
 | |
|         fw = file.write
 | |
|         
 | |
|         base_id = getattr(struct.base, "identifier", "")
 | |
| 
 | |
|         if _BPY_STRUCT_FAKE:
 | |
|             if not base_id:
 | |
|                 base_id = _BPY_STRUCT_FAKE
 | |
| 
 | |
|         if base_id:
 | |
|             title = "%s(%s)" % (struct.identifier, base_id)
 | |
|         else:
 | |
|             title = struct.identifier
 | |
| 
 | |
|         fw("%s\n%s\n\n" % (title, "=" * len(title)))
 | |
|         
 | |
|         fw(".. module:: bpy.types\n\n")
 | |
|         
 | |
|         base_ids = [base.identifier for base in struct.get_bases()]
 | |
| 
 | |
|         if _BPY_STRUCT_FAKE:
 | |
|             base_ids.append(_BPY_STRUCT_FAKE)
 | |
| 
 | |
|         base_ids.reverse()
 | |
|             
 | |
|         if base_ids:
 | |
|             if len(base_ids) > 1:
 | |
|                 fw("base classes --- ")
 | |
|             else:
 | |
|                 fw("base class --- ")
 | |
| 
 | |
|             fw(", ".join((":class:`%s`" % base_id) for base_id in base_ids))
 | |
|             fw("\n\n")
 | |
|         
 | |
|         subclass_ids = [s.identifier for s in structs.values() if s.base is struct if not rna_info.rna_id_ignore(s.identifier)]
 | |
|         if subclass_ids:
 | |
|             fw("subclasses --- \n" + ", ".join((":class:`%s`" % s) for s in subclass_ids) + "\n\n")
 | |
|         
 | |
|         base_id = getattr(struct.base, "identifier", "")
 | |
|         
 | |
|         if _BPY_STRUCT_FAKE:
 | |
|             if not base_id:
 | |
|                 base_id = _BPY_STRUCT_FAKE
 | |
| 
 | |
|         if base_id:
 | |
|             fw(".. class:: %s(%s)\n\n" % (struct.identifier, base_id))
 | |
|         else:
 | |
|             fw(".. class:: %s\n\n" % struct.identifier)
 | |
| 
 | |
|         fw("   %s\n\n" % struct.description)
 | |
|         
 | |
|         # properties sorted in alphabetical order
 | |
|         sorted_struct_properties = struct.properties[:]
 | |
|         sorted_struct_properties.sort(key=lambda prop: prop.identifier)
 | |
| 
 | |
|         for prop in sorted_struct_properties:
 | |
|             type_descr = prop.get_type_description(class_fmt=":class:`%s`")
 | |
|             # readonly properties use "data" directive, variables properties use "attribute" directive
 | |
|             if 'readonly' in type_descr:
 | |
|                 fw("   .. data:: %s\n\n" % prop.identifier)
 | |
|             else:
 | |
|                 fw("   .. attribute:: %s\n\n" % prop.identifier)
 | |
|             if prop.description:
 | |
|                 fw("      %s\n\n" % prop.description)
 | |
|             fw("      :type: %s\n\n" % type_descr)
 | |
|         
 | |
|         # python attributes
 | |
|         py_properties = struct.get_py_properties()
 | |
|         py_prop = None
 | |
|         for identifier, py_prop in py_properties:
 | |
|             pyprop2sphinx("   ", fw, identifier, py_prop)
 | |
|         del py_properties, py_prop
 | |
| 
 | |
|         for func in struct.functions:
 | |
|             args_str = ", ".join(prop.get_arg_default(force=False) for prop in func.args)
 | |
| 
 | |
|             fw("   .. %s:: %s(%s)\n\n" % ("classmethod" if func.is_classmethod else "method", func.identifier, args_str))
 | |
|             fw("      %s\n\n" % func.description)
 | |
|             
 | |
|             for prop in func.args:
 | |
|                 write_param("      ", fw, prop)
 | |
| 
 | |
|             if len(func.return_values) == 1:
 | |
|                 write_param("      ", fw, func.return_values[0], is_return=True)
 | |
|             elif func.return_values: # multiple return values
 | |
|                 fw("      :return (%s):\n" % ", ".join(prop.identifier for prop in func.return_values))
 | |
|                 for prop in func.return_values:
 | |
|                     type_descr = prop.get_type_description(as_ret=True, class_fmt=":class:`%s`")
 | |
|                     descr = prop.description
 | |
|                     if not descr:
 | |
|                         descr = prop.name
 | |
|                     fw("         `%s`, %s, %s\n\n" % (prop.identifier, descr, type_descr))
 | |
| 
 | |
|             fw("\n")
 | |
| 
 | |
| 
 | |
|         # python methods
 | |
|         py_funcs = struct.get_py_functions()
 | |
|         py_func = None
 | |
|         
 | |
|         for identifier, py_func in py_funcs:
 | |
|             pyfunc2sphinx("   ", fw, identifier, py_func, is_class=True)
 | |
|         del py_funcs, py_func
 | |
| 
 | |
|         lines = []
 | |
| 
 | |
|         if struct.base or _BPY_STRUCT_FAKE:
 | |
|             bases = list(reversed(struct.get_bases()))
 | |
| 
 | |
|             # props
 | |
|             lines[:] = []
 | |
|             
 | |
|             if _BPY_STRUCT_FAKE:
 | |
|                 descr_items = [(key, descr) for key, descr in sorted(bpy.types.Struct.__bases__[0].__dict__.items()) if not key.startswith("__")]
 | |
|             
 | |
|             if _BPY_STRUCT_FAKE:
 | |
|                 for key, descr in descr_items:
 | |
|                     if type(descr) == GetSetDescriptorType:
 | |
|                         lines.append("   * :class:`%s.%s`\n" % (_BPY_STRUCT_FAKE, key))
 | |
| 
 | |
|             for base in bases:
 | |
|                 for prop in base.properties:
 | |
|                     lines.append("   * :class:`%s.%s`\n" % (base.identifier, prop.identifier))
 | |
| 
 | |
|                 for identifier, py_prop in base.get_py_properties():
 | |
|                     lines.append("   * :class:`%s.%s`\n" % (base.identifier, identifier))
 | |
|                     
 | |
|                 for identifier, py_prop in base.get_py_properties():
 | |
|                     lines.append("   * :class:`%s.%s`\n" % (base.identifier, identifier))
 | |
|             
 | |
|             if lines:
 | |
|                 fw(".. rubric:: Inherited Properties\n\n")
 | |
| 
 | |
|                 fw(".. hlist::\n")
 | |
|                 fw("   :columns: 2\n\n")
 | |
| 
 | |
|                 for line in lines:
 | |
|                     fw(line)
 | |
|                 fw("\n")
 | |
| 
 | |
| 
 | |
|             # funcs
 | |
|             lines[:] = []
 | |
| 
 | |
|             if _BPY_STRUCT_FAKE:
 | |
|                 for key, descr in descr_items:
 | |
|                     if type(descr) == MethodDescriptorType:
 | |
|                         lines.append("   * :class:`%s.%s`\n" % (_BPY_STRUCT_FAKE, key))
 | |
| 
 | |
|             for base in bases:
 | |
|                 for func in base.functions:
 | |
|                     lines.append("   * :class:`%s.%s`\n" % (base.identifier, func.identifier))
 | |
|                 for identifier, py_func in base.get_py_functions():
 | |
|                     lines.append("   * :class:`%s.%s`\n" % (base.identifier, identifier))
 | |
| 
 | |
|             if lines:
 | |
|                 fw(".. rubric:: Inherited Functions\n\n")
 | |
| 
 | |
|                 fw(".. hlist::\n")
 | |
|                 fw("   :columns: 2\n\n")
 | |
| 
 | |
|                 for line in lines:
 | |
|                     fw(line)
 | |
|                 fw("\n")
 | |
|             
 | |
|             lines[:] = []
 | |
| 
 | |
| 
 | |
|         if struct.references:
 | |
|             # use this otherwise it gets in the index for a normal heading.
 | |
|             fw(".. rubric:: References\n\n")
 | |
| 
 | |
|             fw(".. hlist::\n")
 | |
|             fw("   :columns: 2\n\n")
 | |
| 
 | |
|             for ref in struct.references:
 | |
|                 ref_split = ref.split(".")
 | |
|                 if len(ref_split) > 2:
 | |
|                     ref = ref_split[-2] + "." + ref_split[-1]
 | |
|                 fw("   * :class:`%s`\n" % ref)
 | |
|             fw("\n")
 | |
| 
 | |
| 
 | |
|     for struct in structs.values():
 | |
|         # TODO, rna_info should filter these out!
 | |
|         if "_OT_" in struct.identifier:
 | |
|             continue
 | |
|         write_struct(struct)
 | |
|         
 | |
|     # special case, bpy_struct
 | |
|     if _BPY_STRUCT_FAKE:
 | |
|         filepath = os.path.join(BASEPATH, "bpy.types.%s.rst" % _BPY_STRUCT_FAKE)
 | |
|         file = open(filepath, "w")
 | |
|         fw = file.write
 | |
| 
 | |
|         fw("%s\n" % _BPY_STRUCT_FAKE)
 | |
|         fw("=" * len(_BPY_STRUCT_FAKE) + "\n")
 | |
|         fw("\n")
 | |
|         fw(".. module:: bpy.types\n")
 | |
|         fw("\n")
 | |
| 
 | |
|         subclass_ids = [s.identifier for s in structs.values() if s.base is None if not rna_info.rna_id_ignore(s.identifier)]
 | |
|         if subclass_ids:
 | |
|             fw("subclasses --- \n" + ", ".join((":class:`%s`" % s) for s in sorted(subclass_ids)) + "\n\n")
 | |
| 
 | |
|         fw(".. class:: %s\n\n" % _BPY_STRUCT_FAKE)
 | |
|         fw("   built-in base class for all classes in bpy.types.\n\n")
 | |
|         fw("   .. note::\n\n")
 | |
|         fw("      Note that bpy.types.%s is not actually available from within blender, it only exists for the purpose of documentation.\n\n" % _BPY_STRUCT_FAKE)
 | |
| 
 | |
|         descr_items = [(key, descr) for key, descr in sorted(bpy.types.Struct.__bases__[0].__dict__.items()) if not key.startswith("__")]
 | |
| 
 | |
|         for key, descr in descr_items:
 | |
|             if type(descr) == MethodDescriptorType: # GetSetDescriptorType, GetSetDescriptorType's are not documented yet
 | |
|                 py_descr2sphinx("   ", fw, descr, "bpy.types", _BPY_STRUCT_FAKE, key)
 | |
| 
 | |
|         for key, descr in descr_items:
 | |
|             if type(descr) == GetSetDescriptorType:
 | |
|                 py_descr2sphinx("   ", fw, descr, "bpy.types", _BPY_STRUCT_FAKE, key)
 | |
| 
 | |
| 
 | |
|     # operators
 | |
|     def write_ops():
 | |
|         API_BASEURL='https://svn.blender.org/svnroot/bf-blender/trunk/blender/release/scripts'
 | |
|         fw = None
 | |
|         last_mod = ''
 | |
|         
 | |
|         for op_key in sorted(ops.keys()):
 | |
|             op = ops[op_key]
 | |
|             
 | |
|             if last_mod != op.module_name:
 | |
|                 filepath = os.path.join(BASEPATH, "bpy.ops.%s.rst" % op.module_name)
 | |
|                 file = open(filepath, "w")
 | |
|                 fw = file.write
 | |
|                 
 | |
|                 title = "%s Operators"  % (op.module_name[0].upper() + op.module_name[1:])
 | |
|                 fw("%s\n%s\n\n" % (title, "=" * len(title)))
 | |
|                 
 | |
|                 fw(".. module:: bpy.ops.%s\n\n" % op.module_name)
 | |
|                 last_mod = op.module_name
 | |
| 
 | |
|             args_str = ", ".join(prop.get_arg_default(force=True) for prop in op.args)
 | |
|             fw(".. function:: %s(%s)\n\n" % (op.func_name, args_str))
 | |
| 
 | |
|             # if the description isn't valid, we output the standard warning 
 | |
|             # with a link to the wiki so that people can help
 | |
|             if not op.description or op.description == "(undocumented operator)":
 | |
|                 operator_description = undocumented_message('bpy.ops',op.module_name,op.func_name)
 | |
|             else:
 | |
|                 operator_description = op.description
 | |
| 
 | |
|             fw("   %s\n\n" % operator_description)
 | |
|             for prop in op.args:
 | |
|                 write_param("   ", fw, prop)
 | |
|             if op.args:
 | |
|                 fw("\n")
 | |
| 
 | |
|             location = op.get_location()
 | |
|             if location != (None, None):
 | |
|                 fw("   :file: `%s <%s/%s>`_:%d\n\n" % (location[0],API_BASEURL,location[0],location[1]))
 | |
|     
 | |
|     write_ops()
 | |
| 
 | |
|     file.close()
 | |
| 
 | |
| def main():
 | |
|     import bpy
 | |
|     if 'bpy' not in dir():
 | |
|         print("\nError, this script must run from inside blender2.5")
 | |
|         print(script_help_msg)
 | |
|     else:
 | |
|         import shutil
 | |
| 
 | |
|         path_in = 'source/blender/python/doc/sphinx-in'
 | |
|         path_out = 'source/blender/python/doc/sphinx-out'
 | |
|         path_examples = 'source/blender/python/doc/examples'
 | |
|         # only for partial updates
 | |
|         path_in_tmp = path_in + "-tmp"
 | |
| 
 | |
|         if not os.path.exists(path_in):
 | |
|             os.mkdir(path_in)
 | |
| 
 | |
|         for f in os.listdir(path_examples):
 | |
|             if f.endswith(".py"):
 | |
|                 EXAMPLE_SET.add(os.path.splitext(f)[0])
 | |
| 
 | |
| 
 | |
|         # only for full updates
 | |
|         if _BPY_FULL_REBUILD:
 | |
|             shutil.rmtree(path_in, True)
 | |
|             shutil.rmtree(path_out, True)
 | |
|         else:
 | |
|             # write here, then move
 | |
|             shutil.rmtree(path_in_tmp, True)
 | |
| 
 | |
|         rna2sphinx(path_in_tmp)
 | |
| 
 | |
|         if not _BPY_FULL_REBUILD:
 | |
|             import filecmp
 | |
| 
 | |
|             # now move changed files from 'path_in_tmp' --> 'path_in'
 | |
|             file_list_path_in = set(os.listdir(path_in))
 | |
|             file_list_path_in_tmp = set(os.listdir(path_in_tmp))
 | |
|             
 | |
|             # remove deprecated files that have been removed.
 | |
|             for f in sorted(file_list_path_in):
 | |
|                 if f not in file_list_path_in_tmp:
 | |
|                     print("\tdeprecated: %s" % f)
 | |
|                     os.remove(os.path.join(path_in, f))
 | |
| 
 | |
|             # freshen with new files.
 | |
|             for f in sorted(file_list_path_in_tmp):
 | |
|                 f_from = os.path.join(path_in_tmp, f)
 | |
|                 f_to = os.path.join(path_in, f)
 | |
| 
 | |
|                 do_copy = True
 | |
|                 if f in file_list_path_in:
 | |
|                     if filecmp.cmp(f_from, f_to):
 | |
|                         do_copy = False
 | |
|                 
 | |
|                 if do_copy:
 | |
|                     print("\tupdating: %s" % f)
 | |
|                     shutil.copy(f_from, f_to)
 | |
|                 '''else:
 | |
|                     print("\tkeeping: %s" % f) # eh, not that useful'''
 | |
| 
 | |
| 
 | |
|         EXAMPLE_SET_UNUSED = EXAMPLE_SET - EXAMPLE_SET_USED
 | |
|         if EXAMPLE_SET_UNUSED:
 | |
|             print("\nUnused examples found in '%s'..." % path_examples)
 | |
|             for f in EXAMPLE_SET_UNUSED:
 | |
|                 print("    %s.py" % f)
 | |
|             print("  %d total\n" % len(EXAMPLE_SET_UNUSED))
 | |
| 
 | |
|     import sys
 | |
|     sys.exit()
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     main()
 |