Doc generator now makes 'bpy.context' api reference.
[blender-staging.git] / doc / python_api / sphinx_doc_gen.py
index c1e614aa23f90bba863347c34735ce515fba5708..68c14a75c5b36ee3050dec27e50ac39ee47695d0 100644 (file)
@@ -18,6 +18,8 @@
  #
  # #**** END GPL LICENSE BLOCK #****
 
+# <pep8 compliant>
+
 script_help_msg = '''
 Usage:
 
@@ -31,11 +33,11 @@ For HTML generation
   assuming that ./blender.bin is or links to the blender executable
 
 - Generate html docs by running...
-    
+
     sphinx-build doc/python_api/sphinx-in doc/python_api/sphinx-out
 
   assuming that you have sphinx 0.6.7 installed
-  
+
 For PDF generation
 ------------------
 - After you have built doc/python_api/sphinx-in (see above), run:
@@ -51,7 +53,6 @@ import os
 import inspect
 import bpy
 import rna_info
-reload(rna_info)
 
 # lame, python wont give some access
 ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
@@ -64,11 +65,16 @@ 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&section=new&preload=Dev:2.5/Py/API/Documentation/Contribute/Howto-message" \
-        "&preloadtitle=%s.%s.%s>`_)\n\n" % (module_name, type_name, identifier)
+    if str(type_name).startswith('<module'):
+        preloadtitle = '%s.%s' % (module_name, identifier)
+    else:
+        preloadtitle = '%s.%s.%s' % (module_name, type_name, identifier)
+    message = "Undocumented (`contribute "\
+        "<http://wiki.blender.org/index.php/Dev:2.5/Py/API/Documentation/Contribute"\
+        "?action=edit&section=new&preload=Dev:2.5/Py/API/Documentation/Contribute/Howto-message"\
+        "&preloadtitle=%s>`_)\n\n" % preloadtitle
     return message
 
 
@@ -77,10 +83,12 @@ 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
+    if val < -10000000:
+        return '-inf'
+    elif val > 10000000:
+        return 'inf'
+    elif type(val) == float:
+        return '%g' % val
     else:
         return str(val)
 
@@ -135,7 +143,7 @@ def pyfunc2sphinx(ident, fw, identifier, py_func, is_class=True):
 
     if not is_class:
         func_type = "function"
-        
+
         # ther rest are class methods
     elif arg_str.startswith("(self, "):
         arg_str = "(" + arg_str[7:]
@@ -152,14 +160,14 @@ def pyfunc2sphinx(ident, fw, identifier, py_func, is_class=True):
         fw("\n")
 
 
-def py_descr2sphinx(ident, fw, descr, module_name, type_name, identifier):    
+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)
@@ -176,7 +184,7 @@ def py_c_func2sphinx(ident, fw, module_name, type_name, identifier, py_func, is_
     '''
     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)
@@ -204,26 +212,36 @@ 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 key.startswith("__"):
+            continue
+        # naughty, we also add getset's into PyStructs, this is not typical py but also not incorrect.
+        if type(descr) == types.GetSetDescriptorType:  # 'bpy_app_type' name is only used for examples and messages
+            py_descr2sphinx("", fw, descr, module_name, "bpy_app_type", key)
+            attribute_set.add(key)
+    for key, descr in sorted(type(module).__dict__.items()):
+        if key.startswith("__"):
+            continue
+
         if type(descr) == types.MemberDescriptorType:
             if descr.__doc__:
                 fw(".. data:: %s\n\n" % key)
@@ -231,7 +249,7 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
                 attribute_set.add(key)
                 fw("\n")
     del key, descr
-    
+
     classes = []
 
     for attribute in sorted(dir(module)):
@@ -240,16 +258,16 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
             if attribute in attribute_set:
                 continue
 
-            if attribute.startswith("n_"): # annoying exception, needed for bpy.app
+            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
+            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)
@@ -296,6 +314,117 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
     file.close()
 
 
+def pycontext2sphinx(BASEPATH):
+    # Only use once. very irregular
+
+    filepath = os.path.join(BASEPATH, "bpy.context.rst")
+    file = open(filepath, "w")
+    fw = file.write
+    fw("Context Access (bpy.context)\n")
+    fw("============================\n\n")
+    fw(".. module:: bpy.context\n")
+    fw("\n")
+    fw("The context members available depend on the area of blender which is currently being accessed.\n")
+    fw("\n")
+    fw("Note that all context values are readonly, but may be modified through the data api or by running operators\n\n")
+
+    # nasty, get strings directly from blender because there is no other way to get it
+    import ctypes
+
+    context_strings = (
+        "screen_context_dir",
+        "view3d_context_dir",
+        "buttons_context_dir",
+        "image_context_dir",
+        "node_context_dir",
+        "text_context_dir",
+    )
+
+    # Changes in blender will force errors here
+    type_map = {
+        "active_base": ("ObjectBase", False),
+        "active_bone": ("Bone", False),
+        "active_object": ("Object", False),
+        "active_pose_bone": ("PoseBone", False),
+        "armature": ("Armature", False),
+        "bone": ("Bone", False),
+        "brush": ("Brush", False),
+        "camera": ("Camera", False),
+        "cloth": ("ClothModifier", False),
+        "collision": ("CollisionModifier", False),
+        "curve": ("Curve", False),
+        "edit_bone": ("EditBone", False),
+        "edit_image": ("Image", False),
+        "edit_object": ("Object", False),
+        "edit_text": ("Text", False),
+        "editable_bones": ("EditBone", True),
+        "fluid": ("FluidSimulationModifier", False),
+        "lamp": ("Lamp", False),
+        "lattice": ("Lattice", False),
+        "material": ("Material", False),
+        "material_slot": ("MaterialSlot", False),
+        "mesh": ("Mesh", False),
+        "meta_ball": ("MetaBall", False),
+        "object": ("Object", False),
+        "particle_edit_object": ("Object", False),
+        "particle_system": ("ParticleSystem", False),
+        "particle_system_editable": ("ParticleSystem", False),
+        "pose_bone": ("PoseBone", False),
+        "scene": ("Scene", False),
+        "sculpt_object": ("Object", False),
+        "selectable_bases": ("ObjectBase", True),
+        "selectable_objects": ("Object", True),
+        "selected_bases": ("ObjectBase", True),
+        "selected_bones": ("Bone", True),
+        "selected_editable_bases": ("ObjectBase", True),
+        "selected_editable_bones": ("Bone", True),
+        "selected_editable_objects": ("Object", True),
+        "selected_editable_sequences": ("Sequence", True),
+        "selected_nodes": ("Node", True),
+        "selected_objects": ("Object", True),
+        "selected_pose_bones": ("PoseBone", True),
+        "selected_sequences": ("Sequence", True),
+        "sequences": ("Sequence", True),
+        "smoke": ("SmokeModifier", False),
+        "soft_body": ("SoftBodyModifier", False),
+        "texture": ("Texture", False),
+        "texture_paint_object": ("Object", False),
+        "texture_slot": ("MaterialTextureSlot", False),
+        "vertex_paint_object": ("Object", False),
+        "visible_bases": ("ObjectBase", True),
+        "visible_bones": ("Object", True),
+        "visible_objects": ("Object", True),
+        "visible_pose_bones": ("PoseBone", True),
+        "weight_paint_object": ("Object", False),
+        "world": ("World", False),
+    }
+
+    unique = set()
+    blend_cdll = ctypes.CDLL("")
+    for ctx_str in context_strings:
+        subsection = "%s Context" % ctx_str.split("_")[0].title()
+        fw("\n%s\n%s\n\n" % (subsection, (len(subsection) * '-')))
+
+        attr = ctypes.addressof(getattr(blend_cdll, ctx_str))
+        c_char_p_p = ctypes.POINTER(ctypes.c_char_p)
+        char_array = c_char_p_p.from_address(attr)
+        i = 0
+        while char_array[i] is not None:
+            member = ctypes.string_at(char_array[i]).decode()
+            fw(".. data:: %s\n\n" % member)
+            member_type, is_seq = type_map[member]
+            fw("   :type: %s :class:`bpy.types.%s`\n\n" % ("sequence of " if is_seq else "", member_type))
+            unique.add(member)
+            i += 1
+
+    # generate typemap...
+    # for member in sorted(unique):
+    #     print('        "%s": ("", False),' % member)
+    if len(type_map) > len(unique):
+        raise Exception("Some types are not used: %s" % str([member for member in type_map if member not in unique]))
+    else:
+        pass # will have raised an error above
+
 
 def rna2sphinx(BASEPATH):
 
@@ -311,14 +440,13 @@ def rna2sphinx(BASEPATH):
     file = open(filepath, "w")
     fw = file.write
 
-
-    version_string = bpy.app.version_string.split("(")[0]
+    version_string = ".".join(str(v) for v in bpy.app.version)
     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")
@@ -335,11 +463,11 @@ def rna2sphinx(BASEPATH):
     fw("latex_paper_size = 'a4paper'\n")
     file.close()
 
-
+    # main page needed for sphinx (index.html)
     filepath = os.path.join(BASEPATH, "contents.rst")
     file = open(filepath, "w")
     fw = file.write
-    
+
     fw("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n")
     fw(" Blender Documentation contents\n")
     fw("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n")
@@ -374,15 +502,16 @@ def rna2sphinx(BASEPATH):
     fw("\n")
     fw(".. toctree::\n")
     fw("   :maxdepth: 1\n\n")
-    fw("   bpy.data.rst\n\n") # note: not actually a module
+    fw("   bpy.context.rst\n\n")  # note: not actually a module
+    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")
 
@@ -393,11 +522,13 @@ def rna2sphinx(BASEPATH):
     fw(".. toctree::\n")
     fw("   :maxdepth: 1\n\n")
 
-
     fw("   mathutils.rst\n\n")
+    fw("   mathutils.geometry.rst\n\n")
+    # XXX TODO
+    #fw("   bgl.rst\n\n")
     fw("   blf.rst\n\n")
     fw("   aud.rst\n\n")
-    
+
     # game engine
     fw("===================\n")
     fw("Game Engine Modules\n")
@@ -412,7 +543,6 @@ def rna2sphinx(BASEPATH):
 
     file.close()
 
-
     # internal modules
     filepath = os.path.join(BASEPATH, "bpy.ops.rst")
     file = open(filepath, "w")
@@ -434,7 +564,6 @@ def rna2sphinx(BASEPATH):
     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")
@@ -457,6 +586,8 @@ def rna2sphinx(BASEPATH):
 
     EXAMPLE_SET_USED.add("bpy.data")
 
+    # one of a kind, context doc (uses ctypes to extract info!)
+    pycontext2sphinx(BASEPATH)
 
     # python modules
     from bpy import utils as module
@@ -471,15 +602,24 @@ def rna2sphinx(BASEPATH):
 
     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 mathutils.geometry as module
+    pymodule2sphinx(BASEPATH, "mathutils.geometry", module, "Geometry Utilities (mathutils.geometry)")
+    del module
+
     import blf as module
     pymodule2sphinx(BASEPATH, "blf", module, "Font Drawing (blf)")
     del module
-    
+
+    # XXX TODO
+    #import bgl as module
+    #pymodule2sphinx(BASEPATH, "bgl", module, "Blender OpenGl wrapper (bgl)")
+    #del module
+
     import aud as module
     pymodule2sphinx(BASEPATH, "aud", module, "Audio System (aud)")
     del module
@@ -487,17 +627,16 @@ def rna2sphinx(BASEPATH):
     ## game engine
     import shutil
     # copy2 keeps time/date stamps
-    shutil.copy2(os.path.join(BASEPATH,"..","rst","bge.types.rst"), BASEPATH)
-    shutil.copy2(os.path.join(BASEPATH,"..","rst","bge.logic.rst"), BASEPATH)
-    shutil.copy2(os.path.join(BASEPATH,"..","rst","bge.render.rst"), BASEPATH)
-    shutil.copy2(os.path.join(BASEPATH,"..","rst","bge.events.rst"), BASEPATH)
-
+    shutil.copy2(os.path.join(BASEPATH, "..", "rst", "bge.types.rst"), BASEPATH)
+    shutil.copy2(os.path.join(BASEPATH, "..", "rst", "bge.logic.rst"), BASEPATH)
+    shutil.copy2(os.path.join(BASEPATH, "..", "rst", "bge.render.rst"), BASEPATH)
+    shutil.copy2(os.path.join(BASEPATH, "..", "rst", "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"
@@ -532,7 +671,7 @@ def rna2sphinx(BASEPATH):
         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:
@@ -545,16 +684,16 @@ def rna2sphinx(BASEPATH):
             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 --- ")
@@ -563,13 +702,13 @@ def rna2sphinx(BASEPATH):
 
             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
@@ -580,7 +719,7 @@ def rna2sphinx(BASEPATH):
             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)
@@ -595,7 +734,7 @@ def rna2sphinx(BASEPATH):
             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
@@ -608,13 +747,13 @@ def rna2sphinx(BASEPATH):
 
             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
+            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`")
@@ -625,11 +764,10 @@ def rna2sphinx(BASEPATH):
 
             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
@@ -641,10 +779,10 @@ def rna2sphinx(BASEPATH):
 
             # 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:
@@ -656,10 +794,10 @@ def rna2sphinx(BASEPATH):
 
                 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")
 
@@ -670,7 +808,6 @@ def rna2sphinx(BASEPATH):
                     fw(line)
                 fw("\n")
 
-
             # funcs
             lines[:] = []
 
@@ -694,9 +831,8 @@ def rna2sphinx(BASEPATH):
                 for line in lines:
                     fw(line)
                 fw("\n")
-            
-            lines[:] = []
 
+            lines[:] = []
 
         if struct.references:
             # use this otherwise it gets in the index for a normal heading.
@@ -712,13 +848,12 @@ def rna2sphinx(BASEPATH):
                 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)
@@ -743,41 +878,40 @@ def rna2sphinx(BASEPATH):
         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
+            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'
+        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:])
+
+                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 
+            # 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)
+                operator_description = undocumented_message('bpy.ops', op.module_name, op.func_name)
             else:
                 operator_description = op.description
 
@@ -789,12 +923,13 @@ def rna2sphinx(BASEPATH):
 
             location = op.get_location()
             if location != (None, None):
-                fw("   :file: `%s <%s/%s>`_:%d\n\n" % (location[0],API_BASEURL,location[0],location[1]))
-    
+                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():
@@ -804,9 +939,9 @@ def main():
         import shutil
 
         script_dir = os.path.dirname(__file__)
-        path_in = os.path.join(script_dir,'sphinx-in')
-        path_out = os.path.join(script_dir,'sphinx-out')
-        path_examples = os.path.join(script_dir,'examples')
+        path_in = os.path.join(script_dir, "sphinx-in")
+        path_out = os.path.join(script_dir, "sphinx-out")
+        path_examples = os.path.join(script_dir, "examples")
         # only for partial updates
         path_in_tmp = path_in + "-tmp"
 
@@ -817,7 +952,6 @@ def main():
             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)
@@ -834,7 +968,7 @@ def main():
             # 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:
@@ -850,14 +984,13 @@ def main():
                 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)