- added docs and examples for bpy.app.handlers

- correct error in own last commit for BKE_screen_find_big_area()
This commit is contained in:
Campbell Barton 2011-11-04 04:27:46 +00:00
parent 7e9bc22925
commit 87cd81b162
6 changed files with 153 additions and 53 deletions

View File

@ -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)

View File

@ -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)

View 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)
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)
del key, descr
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)
if attribute.startswith("n_"): # annoying exception, needed for bpy.app
continue
value_type = type(value)
# workaround for bpy.app documenting .index() and .count()
if isinstance(module, tuple) and hasattr(tuple, attribute):
continue
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
value = getattr(module, attribute)
attribute_set.add(attribute)
# TODO, more types...
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...
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")

View 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;

View 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}
};

View 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 *)""},