- added docs and examples for bpy.app.handlers
authorCampbell Barton <ideasman42@gmail.com>
Fri, 4 Nov 2011 04:27:46 +0000 (04:27 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 4 Nov 2011 04:27:46 +0000 (04:27 +0000)
- correct error in own last commit for BKE_screen_find_big_area()

doc/python_api/examples/bpy.app.handlers.1.py [new file with mode: 0644]
doc/python_api/examples/bpy.app.handlers.py [new file with mode: 0644]
doc/python_api/sphinx_doc_gen.py
source/blender/blenkernel/intern/screen.c
source/blender/python/intern/bpy_app_handlers.c
source/gameengine/Ketsji/KX_PythonInit.cpp

diff --git a/doc/python_api/examples/bpy.app.handlers.1.py b/doc/python_api/examples/bpy.app.handlers.1.py
new file mode 100644 (file)
index 0000000..a6591f6
--- /dev/null
@@ -0,0 +1,20 @@
+"""
+Persistent Handler Example
+++++++++++++++++++++++++++
+
+By default handlers are freed when loading new files, in some cases you may
+wan't the handler stay running across multiple files (when the handler is
+part of an addon for example).
+
+For this the :data:`bpy.app.handlers.persistent` decorator needs to be used.
+"""
+
+import bpy
+from bpy.app.handlers import persistent
+
+
+@persistent
+def load_handler(dummy):
+   print("Load Handler:", bpy.data.filepath)
+
+bpy.app.handlers.load_post.append(load_handler)
diff --git a/doc/python_api/examples/bpy.app.handlers.py b/doc/python_api/examples/bpy.app.handlers.py
new file mode 100644 (file)
index 0000000..7c17606
--- /dev/null
@@ -0,0 +1,12 @@
+"""
+Basic Handler Example
++++++++++++++++++++++
+This script shows the most simple example of adding a handler.
+"""
+
+import bpy
+
+def my_handler(scene):
+   print("Frame Change", scene.frame_current)
+
+bpy.app.handlers.frame_change_pre.append(my_handler)
\ No newline at end of file
index 5843e5ddb6c699e1689568ee2c52a1d55ddc4e90..b0127c50b294a3e24b72742c2cbeb5dd9c57a32d 100644 (file)
@@ -50,7 +50,7 @@ For PDF generation
 
 # Check we're running in blender
 if __import__("sys").modules.get("bpy") is None:
-    print("\nError, this script must run from inside blender2.5")
+    print("\nError, this script must run from inside blender")
     print(script_help_msg)
 
     import sys
@@ -70,13 +70,14 @@ else:
     # for testing so doc-builds dont take so long.
     EXCLUDE_MODULES = (
         "bpy.context",
-        "bpy.app",
+        #"bpy.app",
+        #"bpy.app.handlers",
         "bpy.path",
         "bpy.data",
         "bpy.props",
         "bpy.utils",
         "bpy.context",
-        "bpy.types",  # supports filtering
+        "bpy.types",  # supports filtering
         "bpy.ops",  # supports filtering
         "bpy_extras",
         "bge",
@@ -109,6 +110,18 @@ INFO_DOCS = (
     ("info_gotcha.rst", "Gotcha's: some of the problems you may come up against when writing scripts"),
     )
 
+
+# -----------------------------------------------------------------------------
+# configure compile time options
+
+try:
+    __import__("aud")
+except ImportError:
+    print("Warning: Built without 'aud' module, docs incomplete...")
+    EXCLUDE_MODULES = EXCLUDE_MODULES + ("aud", )
+
+
+
 # import rpdb2; rpdb2.start_embedded_debugger('test')
 
 import os
@@ -120,6 +133,7 @@ import rna_info
 ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
 MethodDescriptorType = type(dict.get)
 GetSetDescriptorType = type(int.real)
+from types import MemberDescriptorType
 
 EXAMPLE_SET = set()
 EXAMPLE_SET_USED = set()
@@ -134,6 +148,14 @@ else:
     _BPY_PROP_COLLECTION_ID = "collection"
 
 
+def is_struct_seq(value):
+    return isinstance(value, tuple) and type(tuple) != tuple and hasattr(value, "n_fields")
+
+
+def module_id_as_ref(name):
+    return "mod_" + name.replace(".", "__")
+
+
 def undocumented_message(module_name, type_name, identifier):
     if str(type_name).startswith('<module'):
         preloadtitle = '%s.%s' % (module_name, identifier)
@@ -305,6 +327,10 @@ def py_descr2sphinx(ident, fw, descr, module_name, type_name, identifier):
         fw(ident + ".. attribute:: %s\n\n" % identifier)
         write_indented_lines(ident + "   ", fw, doc, False)
         fw("\n")
+    elif type(descr) == MemberDescriptorType: # same as above but use 'data'
+        fw(ident + ".. data:: %s\n\n" % identifier)
+        write_indented_lines(ident + "   ", fw, doc, False)
+        fw("\n")
     elif type(descr) in (MethodDescriptorType, ClassMethodDescriptorType):
         write_indented_lines(ident, fw, doc, False)
         fw("\n")
@@ -367,6 +393,10 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
 
     write_title(fw, "%s (%s)" % (title, module_name), "=")
 
+    # write reference, annoying since we should be able to direct reference the
+    # modules but we cant always!
+    fw(".. _%s:\n\n" % module_id_as_ref(module_name))
+
     fw(".. module:: %s\n\n" % module_name)
 
     if module.__doc__:
@@ -411,59 +441,91 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
         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)
+
+        # type_name is only used for examples and messages
+        type_name = str(type(module)).strip("<>").split(" ", 1)[-1][1:-1] # "<class 'bpy.app.handlers'>" --> bpy.app.handlers
+        if type(descr) == types.GetSetDescriptorType:
+            py_descr2sphinx("", fw, descr, module_name, type_name, key)
             attribute_set.add(key)
+    descr_sorted = []
     for key, descr in sorted(type(module).__dict__.items()):
         if key.startswith("__"):
             continue
 
-        if type(descr) == types.MemberDescriptorType:
+        if type(descr) == MemberDescriptorType:
             if descr.__doc__:
-                fw(".. data:: %s\n\n" % key)
-                write_indented_lines("   ", fw, descr.__doc__, False)
-                fw("\n")
-                attribute_set.add(key)
-
-    del key, descr
+                value = getattr(module, key, None)
+                value_type = type(value)
+                descr_sorted.append((key, descr, value, type(value)))
+    # sort by the valye type
+    descr_sorted.sort(key=lambda descr_data: str(descr_data[3]))
+    for key, descr, value, value_type in descr_sorted:
+        type_name = value_type.__name__
+        py_descr2sphinx("", fw, descr, module_name, type_name, key)
+
+        if is_struct_seq(value):
+            # ack, cant use typical reference because we double up once here
+            # and one fort he module!
+            full_name = "%s.%s" % (module_name, type_name)
+            fw("   :ref:`%s submodule details <%s>`\n\n\n" % (full_name, module_id_as_ref(full_name))) #  % (module_name, type_name)
+            del full_name
+
+        attribute_set.add(key)
+
+    del key, descr, descr_sorted
 
     classes = []
     submodules = []
 
+    # use this list so we can sort by type
+    module_dir_value_type = []
+
     for attribute in module_dir:
-        if not attribute.startswith("_"):
-            if attribute in attribute_set:
-                continue
+        if attribute.startswith("_"):
+            continue
 
-            if attribute.startswith("n_"):  # annoying exception, needed for bpy.app
-                continue
+        if attribute in attribute_set:
+            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, None, attribute, value, is_class=False)
-            elif value_type == type:
-                classes.append((attribute, value))
-            elif issubclass(value_type, types.ModuleType):
-                submodules.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 of %r type" % (module_name, attribute, value_type.__name__))
-                continue
+        if attribute.startswith("n_"):  # annoying exception, needed for bpy.app
+            continue
+
+        # workaround for bpy.app documenting .index() and .count()
+        if isinstance(module, tuple) and hasattr(tuple, attribute):
+            continue
+
+        value = getattr(module, attribute)
+
+        module_dir_value_type.append((attribute, value, type(value)))
+
+    # sort by str of each type
+    # this way lists, functions etc are grouped.
+    module_dir_value_type.sort(key=lambda triple: str(triple[2]))
+
+    for attribute, value, value_type in module_dir_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, module_name, None, attribute, value, is_class=False)
+        elif value_type == type:
+            classes.append((attribute, value))
+        elif issubclass(value_type, types.ModuleType):
+            submodules.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 of %r type" % (module_name, attribute, value_type.__name__))
+            continue
 
-            attribute_set.add(attribute)
-            # TODO, more types...
+        attribute_set.add(attribute)
+        # TODO, more types...
+    del module_dir_value_type
 
     # TODO, bpy_extras does this already, mathutils not.
     """
@@ -1103,6 +1165,8 @@ def rna2sphinx(BASEPATH):
         fw("   bpy.path.rst\n\n")
     if "bpy.app" not in EXCLUDE_MODULES:
         fw("   bpy.app.rst\n\n")
+    if "bpy.app.handlers" not in EXCLUDE_MODULES:
+        fw("   bpy.app.handlers.rst\n\n")
 
     # C modules
     if "bpy.props" not in EXCLUDE_MODULES:
@@ -1242,6 +1306,10 @@ def rna2sphinx(BASEPATH):
         from bpy import app as module
         pymodule2sphinx(BASEPATH, "bpy.app", module, "Application Data")
 
+    if "bpy.app.handlers" not in EXCLUDE_MODULES:    
+        from bpy.app import handlers as module
+        pymodule2sphinx(BASEPATH, "bpy.app.handlers", module, "Application Handlers")
+
     if "bpy.props" not in EXCLUDE_MODULES:
         from bpy import props as module
         pymodule2sphinx(BASEPATH, "bpy.props", module, "Property Definitions")
index b7f49bbab4738f19855b8707486283a431088a3e..3d28e45f6b77a6aaa921b5587673f4231b34fbf2 100644 (file)
@@ -361,7 +361,7 @@ struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype
 
        for(sa= sc->areabase.first; sa; sa= sa->next) {
                if ((spacetype == -1) || sa->spacetype == spacetype) {
-                       if (min >= sa->winx && min >= sa->winy) {
+                       if (min <= sa->winx && min <= sa->winy) {
                                size= sa->winx*sa->winy;
                                if (size > maxsize) {
                                        maxsize= size;
index 5b8c20bb12d00d8d395f28012e36e22c70be17ef..f130a4bcc5c2e543b306d44bd9ca209a65bea193 100644 (file)
@@ -38,21 +38,21 @@ void bpy_app_generic_callback(struct Main *main, struct ID *id, void *arg);
 static PyTypeObject BlenderAppCbType;
 
 static PyStructSequence_Field app_cb_info_fields[]= {
-       {(char *)"frame_change_pre", NULL},
-       {(char *)"frame_change_post", NULL},
-       {(char *)"render_pre", NULL},
-       {(char *)"render_post", NULL},
-       {(char *)"render_stats", NULL},
-       {(char *)"load_pre", NULL},
-       {(char *)"load_post", NULL},
-       {(char *)"save_pre", NULL},
-       {(char *)"save_post", NULL},
-       {(char *)"scene_update_pre", NULL},
-       {(char *)"scene_update_post", NULL},
+       {(char *)"frame_change_pre",  (char *)"Callback list - on frame change for playback and rendering (before)"},
+       {(char *)"frame_change_post", (char *)"Callback list - on frame change for playback and rendering (after)"},
+       {(char *)"render_pre",        (char *)"Callback list - on render (before)"},
+       {(char *)"render_post",       (char *)"Callback list - on render (after)"},
+       {(char *)"render_stats",      (char *)"Callback list - on printing render statistics"},
+       {(char *)"load_pre",          (char *)"Callback list - on loading a new blend file (before)"},
+       {(char *)"load_post",         (char *)"Callback list - on loading a new blend file (after)"},
+       {(char *)"save_pre",          (char *)"Callback list - on saving a blend file (before)"},
+       {(char *)"save_post",         (char *)"Callback list - on saving a blend file (after)"},
+       {(char *)"scene_update_pre",  (char *)"Callback list - on updating the scenes data (before)"},
+       {(char *)"scene_update_post", (char *)"Callback list - on updating the scenes data (after)"},
 
        /* sets the permanent tag */
 #   define APP_CB_OTHER_FIELDS 1
-       {(char *)"persistent", NULL},
+       {(char *)"persistent",        (char *)"Function decorator for callback functions not to be removed when loading new files"},
 
        {NULL}
 };
index c3a141e74057fcb7dc24c3f1e5582f7c2b961438..02e6ebea71b6c617d31ece204bf165ff1893b277 100644 (file)
@@ -815,7 +815,7 @@ static struct PyMethodDef game_methods[] = {
        {"getAverageFrameRate", (PyCFunction) gPyGetAverageFrameRate, METH_NOARGS, (const char *)"Gets the estimated average frame rate"},
        {"getBlendFileList", (PyCFunction)gPyGetBlendFileList, METH_VARARGS, (const char *)"Gets a list of blend files in the same directory as the current blend file"},
        {"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, (const char *)"Prints GL Extension Info"},
-       {"PrintMemInfo", (PyCFunction)pyPrintStats, METH_NOARGS, (const char *)"Print engine stastics"},
+       {"PrintMemInfo", (PyCFunction)pyPrintStats, METH_NOARGS, (const char *)"Print engine statistics"},
        
        /* library functions */
        {"LibLoad", (PyCFunction)gLibLoad, METH_VARARGS|METH_KEYWORDS, (const char *)""},