Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/python/intern')
-rw-r--r--source/blender/python/intern/CMakeLists.txt4
-rw-r--r--source/blender/python/intern/bpy.c12
-rw-r--r--source/blender/python/intern/bpy.h5
-rw-r--r--source/blender/python/intern/bpy_app.c54
-rw-r--r--source/blender/python/intern/bpy_app_alembic.c2
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c9
-rw-r--r--source/blender/python/intern/bpy_app_ffmpeg.c4
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c2
-rw-r--r--source/blender/python/intern/bpy_app_ocio.c2
-rw-r--r--source/blender/python/intern/bpy_app_oiio.c2
-rw-r--r--source/blender/python/intern/bpy_app_opensubdiv.c2
-rw-r--r--source/blender/python/intern/bpy_app_openvdb.c2
-rw-r--r--source/blender/python/intern/bpy_app_sdl.c6
-rw-r--r--source/blender/python/intern/bpy_app_translations.c22
-rw-r--r--source/blender/python/intern/bpy_app_usd.c2
-rw-r--r--source/blender/python/intern/bpy_capi_utils.c10
-rw-r--r--source/blender/python/intern/bpy_capi_utils.h4
-rw-r--r--source/blender/python/intern/bpy_driver.c6
-rw-r--r--source/blender/python/intern/bpy_interface.c128
-rw-r--r--source/blender/python/intern/bpy_interface_atexit.c2
-rw-r--r--source/blender/python/intern/bpy_library_load.c14
-rw-r--r--source/blender/python/intern/bpy_msgbus.c6
-rw-r--r--source/blender/python/intern/bpy_operator.c55
-rw-r--r--source/blender/python/intern/bpy_props.c26
-rw-r--r--source/blender/python/intern/bpy_rna.c366
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c12
-rw-r--r--source/blender/python/intern/bpy_rna_gizmo.c4
-rw-r--r--source/blender/python/intern/bpy_rna_types_capi.c2
-rw-r--r--source/blender/python/intern/bpy_rna_ui.c3
-rw-r--r--source/blender/python/intern/bpy_utils_previews.c30
-rw-r--r--source/blender/python/intern/bpy_utils_units.c12
31 files changed, 482 insertions, 328 deletions
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 6c3f422d3f0..772b31fd9d8 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -341,6 +341,8 @@ if(WITH_XR_OPENXR)
add_definitions(-DWITH_XR_OPENXR)
endif()
-add_definitions(${GL_DEFINITIONS})
+if(WITH_POTRACE)
+ add_definitions(-DWITH_POTRACE)
+endif()
blender_add_lib(bf_python "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index de8fd87db58..804a28d0ebc 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -35,6 +35,8 @@
#include "RNA_access.h"
#include "RNA_types.h"
+#include "GPU_state.h"
+
#include "bpy.h"
#include "bpy_app.h"
#include "bpy_capi_utils.h"
@@ -145,7 +147,7 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec
return list;
}
-// PyDoc_STRVAR(bpy_user_resource_doc[] = // now in bpy/utils.py
+// PyDoc_STRVAR(bpy_user_resource_doc[] = /* now in bpy/utils.py */
static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
const struct PyC_StringEnumItems type_items[] = {
@@ -330,6 +332,9 @@ static PyMethodDef meth_bpy_escape_identifier = {
static PyObject *bpy_import_test(const char *modname)
{
PyObject *mod = PyImport_ImportModuleLevel(modname, NULL, NULL, NULL, 0);
+
+ GPU_bgl_end();
+
if (mod) {
Py_DECREF(mod);
}
@@ -344,7 +349,7 @@ static PyObject *bpy_import_test(const char *modname)
/******************************************************************************
* Description: Creates the bpy module and adds it to sys.modules for importing
******************************************************************************/
-void BPy_init_modules(void)
+void BPy_init_modules(struct bContext *C)
{
PointerRNA ctx_ptr;
PyObject *mod;
@@ -395,8 +400,7 @@ void BPy_init_modules(void)
PyModule_AddObject(mod, "_utils_previews", BPY_utils_previews_module());
PyModule_AddObject(mod, "msgbus", BPY_msgbus_module());
- /* bpy context */
- RNA_pointer_create(NULL, &RNA_Context, (void *)BPy_GetContext(), &ctx_ptr);
+ RNA_pointer_create(NULL, &RNA_Context, C, &ctx_ptr);
bpy_context_module = (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ctx_ptr);
/* odd that this is needed, 1 ref on creation and another for the module
* but without we get a crash on exit */
diff --git a/source/blender/python/intern/bpy.h b/source/blender/python/intern/bpy.h
index 744bf903443..25a047edfb5 100644
--- a/source/blender/python/intern/bpy.h
+++ b/source/blender/python/intern/bpy.h
@@ -24,7 +24,9 @@
extern "C" {
#endif
-void BPy_init_modules(void);
+struct bContext;
+
+void BPy_init_modules(struct bContext *C);
extern PyObject *bpy_package_py;
/* bpy_interface_atexit.c */
@@ -33,6 +35,7 @@ void BPY_atexit_unregister(void);
extern struct CLG_LogRef *BPY_LOG_CONTEXT;
extern struct CLG_LogRef *BPY_LOG_RNA;
+extern struct CLG_LogRef *BPY_LOG_INTERFACE;
#ifdef __cplusplus
}
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index f0de05f95b3..02ab001dbf6 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -82,6 +82,7 @@ static PyTypeObject BlenderAppType;
static PyStructSequence_Field app_info_fields[] = {
{"version", "The Blender version as a tuple of 3 numbers. eg. (2, 83, 1)"},
+ {"version_file", "The blend file version, compatible with ``bpy.data.version``"},
{"version_string", "The Blender version formatted as a string"},
{"version_cycle", "The release status of this build alpha/beta/rc/release"},
{"version_char", "Deprecated, always an empty string"},
@@ -126,17 +127,7 @@ static PyStructSequence_Field app_info_fields[] = {
};
PyDoc_STRVAR(bpy_app_doc,
- "This module contains application values that remain unchanged during runtime.\n"
- "\n"
- "Submodules:\n"
- "\n"
- ".. toctree::\n"
- " :maxdepth: 1\n"
- "\n"
- " bpy.app.handlers.rst\n"
- " bpy.app.icons.rst\n"
- " bpy.app.timers.rst\n"
- " bpy.app.translations.rst\n");
+ "This module contains application values that remain unchanged during runtime.");
static PyStructSequence_Desc app_info_desc = {
"bpy.app", /* name */
@@ -161,6 +152,8 @@ static PyObject *make_app_info(void)
SetObjItem(
PyC_Tuple_Pack_I32(BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_VERSION_PATCH));
+ SetObjItem(PyC_Tuple_Pack_I32(
+ BLENDER_FILE_VERSION / 100, BLENDER_FILE_VERSION % 100, BLENDER_FILE_SUBVERSION));
SetStrItem(BKE_blender_version_string());
SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE));
@@ -170,7 +163,7 @@ static PyObject *make_app_info(void)
SetObjItem(PyBool_FromLong(G.factory_startup));
/* build info, use bytes since we can't assume _any_ encoding:
- * see patch [#30154] for issue */
+ * see patch T30154 for issue */
#ifdef BUILD_DATE
SetBytesItem(build_date);
SetBytesItem(build_time);
@@ -302,36 +295,13 @@ static int bpy_app_global_flag_set__only_disable(PyObject *UNUSED(self),
return bpy_app_global_flag_set(NULL, value, closure);
}
-#define BROKEN_BINARY_PATH_PYTHON_HACK
-
PyDoc_STRVAR(bpy_app_binary_path_python_doc,
- "String, the path to the python executable (read-only)");
-static PyObject *bpy_app_binary_path_python_get(PyObject *self, void *UNUSED(closure))
+ "String, the path to the python executable (read-only). "
+ "Deprecated! Use ``sys.executable`` instead.");
+static PyObject *bpy_app_binary_path_python_get(PyObject *UNUSED(self), void *UNUSED(closure))
{
- /* refcount is held in BlenderAppType.tp_dict */
- static PyObject *ret = NULL;
-
- if (ret == NULL) {
- /* only run once */
- char fullpath[1024];
- BKE_appdir_program_python_search(
- fullpath, sizeof(fullpath), PY_MAJOR_VERSION, PY_MINOR_VERSION);
- ret = PyC_UnicodeFromByte(fullpath);
-#ifdef BROKEN_BINARY_PATH_PYTHON_HACK
- Py_INCREF(ret);
- UNUSED_VARS(self);
-#else
- PyDict_SetItem(
- BlenderAppType.tp_dict,
- /* XXX BAAAADDDDDD! self is not a PyDescr at all! it's bpy.app!!! */ PyDescr_NAME(self),
- ret);
-#endif
- }
- else {
- Py_INCREF(ret);
- }
-
- return ret;
+ PyErr_Warn(PyExc_RuntimeWarning, "Use 'sys.executable' instead of 'binary_path_python'!");
+ return Py_INCREF_RET(PySys_GetObject("executable"));
}
PyDoc_STRVAR(bpy_app_debug_value_doc,
@@ -383,7 +353,7 @@ PyDoc_STRVAR(bpy_app_preview_render_size_doc,
"Reference size for icon/preview renders (read-only)");
static PyObject *bpy_app_preview_render_size_get(PyObject *UNUSED(self), void *closure)
{
- return PyLong_FromLong((long)UI_preview_render_size(POINTER_AS_INT(closure)));
+ return PyLong_FromLong((long)UI_icon_preview_to_render_size(POINTER_AS_INT(closure)));
}
static PyObject *bpy_app_autoexec_fail_message_get(PyObject *UNUSED(self), void *UNUSED(closure))
@@ -532,7 +502,7 @@ PyObject *BPY_app_struct(void)
BlenderAppType.tp_init = NULL;
BlenderAppType.tp_new = NULL;
BlenderAppType.tp_hash = (hashfunc)
- _Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+ _Py_HashPointer; /* without this we can't do set(sys.modules) T29635. */
/* kindof a hack ontop of PyStructSequence */
py_struct_seq_getset_init();
diff --git a/source/blender/python/intern/bpy_app_alembic.c b/source/blender/python/intern/bpy_app_alembic.c
index dc7632baeef..d5640045977 100644
--- a/source/blender/python/intern/bpy_app_alembic.c
+++ b/source/blender/python/intern/bpy_app_alembic.c
@@ -100,7 +100,7 @@ PyObject *BPY_app_alembic_struct(void)
BlenderAppABCType.tp_init = NULL;
BlenderAppABCType.tp_new = NULL;
BlenderAppABCType.tp_hash = (hashfunc)
- _Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+ _Py_HashPointer; /* without this we can't do set(sys.modules) T29635. */
return ret;
}
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index cc97f6dec94..aaceb7b393f 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -61,6 +61,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{"usd", NULL},
{"fluid", NULL},
{"xr_openxr", NULL},
+ {"potrace", NULL},
{NULL},
};
@@ -282,6 +283,12 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_POTRACE
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#undef SetObjIncref
return builtopts_info;
@@ -299,7 +306,7 @@ PyObject *BPY_app_build_options_struct(void)
BlenderAppBuildOptionsType.tp_init = NULL;
BlenderAppBuildOptionsType.tp_new = NULL;
BlenderAppBuildOptionsType.tp_hash = (hashfunc)
- _Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+ _Py_HashPointer; /* without this we can't do set(sys.modules) T29635. */
return ret;
}
diff --git a/source/blender/python/intern/bpy_app_ffmpeg.c b/source/blender/python/intern/bpy_app_ffmpeg.c
index 193b0385044..4e396668450 100644
--- a/source/blender/python/intern/bpy_app_ffmpeg.c
+++ b/source/blender/python/intern/bpy_app_ffmpeg.c
@@ -75,7 +75,7 @@ static PyObject *make_ffmpeg_info(void)
return NULL;
}
-#if 0 // UNUSED
+#if 0 /* UNUSED */
# define SetIntItem(flag) PyStructSequence_SET_ITEM(ffmpeg_info, pos++, PyLong_FromLong(flag))
#endif
#ifndef WITH_FFMPEG
@@ -140,7 +140,7 @@ PyObject *BPY_app_ffmpeg_struct(void)
BlenderAppFFmpegType.tp_init = NULL;
BlenderAppFFmpegType.tp_new = NULL;
BlenderAppFFmpegType.tp_hash = (hashfunc)
- _Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+ _Py_HashPointer; /* without this we can't do set(sys.modules) T29635. */
return ret;
}
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index a874e23ff32..1e81621246e 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -232,7 +232,7 @@ PyObject *BPY_app_handlers_struct(void)
BlenderAppCbType.tp_init = NULL;
BlenderAppCbType.tp_new = NULL;
BlenderAppCbType.tp_hash = (hashfunc)
- _Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+ _Py_HashPointer; /* without this we can't do set(sys.modules) T29635. */
/* assign the C callbacks */
if (ret) {
diff --git a/source/blender/python/intern/bpy_app_ocio.c b/source/blender/python/intern/bpy_app_ocio.c
index bbfc734a77f..3a36e90018f 100644
--- a/source/blender/python/intern/bpy_app_ocio.c
+++ b/source/blender/python/intern/bpy_app_ocio.c
@@ -104,7 +104,7 @@ PyObject *BPY_app_ocio_struct(void)
BlenderAppOCIOType.tp_init = NULL;
BlenderAppOCIOType.tp_new = NULL;
BlenderAppOCIOType.tp_hash = (hashfunc)
- _Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+ _Py_HashPointer; /* without this we can't do set(sys.modules) T29635. */
return ret;
}
diff --git a/source/blender/python/intern/bpy_app_oiio.c b/source/blender/python/intern/bpy_app_oiio.c
index 1f65641606d..0038f982170 100644
--- a/source/blender/python/intern/bpy_app_oiio.c
+++ b/source/blender/python/intern/bpy_app_oiio.c
@@ -100,7 +100,7 @@ PyObject *BPY_app_oiio_struct(void)
BlenderAppOIIOType.tp_init = NULL;
BlenderAppOIIOType.tp_new = NULL;
BlenderAppOIIOType.tp_hash = (hashfunc)
- _Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+ _Py_HashPointer; /* without this we can't do set(sys.modules) T29635. */
return ret;
}
diff --git a/source/blender/python/intern/bpy_app_opensubdiv.c b/source/blender/python/intern/bpy_app_opensubdiv.c
index 09cd6201831..90aab2a4500 100644
--- a/source/blender/python/intern/bpy_app_opensubdiv.c
+++ b/source/blender/python/intern/bpy_app_opensubdiv.c
@@ -96,7 +96,7 @@ PyObject *BPY_app_opensubdiv_struct(void)
/* prevent user from creating new instances */
BlenderAppOpenSubdivType.tp_init = NULL;
BlenderAppOpenSubdivType.tp_new = NULL;
- /* without this we can't do set(sys.modules) [#29635] */
+ /* without this we can't do set(sys.modules) T29635. */
BlenderAppOpenSubdivType.tp_hash = (hashfunc)_Py_HashPointer;
return ret;
diff --git a/source/blender/python/intern/bpy_app_openvdb.c b/source/blender/python/intern/bpy_app_openvdb.c
index 9958029dd0a..c98c6ec0137 100644
--- a/source/blender/python/intern/bpy_app_openvdb.c
+++ b/source/blender/python/intern/bpy_app_openvdb.c
@@ -104,7 +104,7 @@ PyObject *BPY_app_openvdb_struct(void)
BlenderAppOVDBType.tp_init = NULL;
BlenderAppOVDBType.tp_new = NULL;
BlenderAppOVDBType.tp_hash = (hashfunc)
- _Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+ _Py_HashPointer; /* without this we can't do set(sys.modules) T29635. */
return ret;
}
diff --git a/source/blender/python/intern/bpy_app_sdl.c b/source/blender/python/intern/bpy_app_sdl.c
index a3f9fdc67c1..645119c1c5d 100644
--- a/source/blender/python/intern/bpy_app_sdl.c
+++ b/source/blender/python/intern/bpy_app_sdl.c
@@ -89,7 +89,7 @@ static PyObject *make_sdl_info(void)
SDL_GetVersion(&version);
sdl_available = true;
}
-# else // WITH_SDL_DYNLOAD=OFF
+# else /* WITH_SDL_DYNLOAD=OFF */
sdl_available = true;
# if SDL_MAJOR_VERSION >= 2
SDL_GetVersion(&version);
@@ -107,7 +107,7 @@ static PyObject *make_sdl_info(void)
}
SetObjItem(PyBool_FromLong(sdl_available));
-#else // WITH_SDL=OFF
+#else /* WITH_SDL=OFF */
SetObjItem(PyBool_FromLong(0));
SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0));
SetStrItem("Unknown");
@@ -137,7 +137,7 @@ PyObject *BPY_app_sdl_struct(void)
BlenderAppSDLType.tp_init = NULL;
BlenderAppSDLType.tp_new = NULL;
BlenderAppSDLType.tp_hash = (hashfunc)
- _Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+ _Py_HashPointer; /* without this we can't do set(sys.modules) T29635. */
return ret;
}
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index f95261df6b2..ee64d0a409c 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -420,9 +420,9 @@ static BLT_i18n_contexts_descriptor _contexts[] = BLT_I18NCONTEXTS_DESC;
static PyStructSequence_Field app_translations_contexts_fields[ARRAY_SIZE(_contexts)] = {{NULL}};
static PyStructSequence_Desc app_translations_contexts_desc = {
- "bpy.app.translations.contexts", /* name */
- "This named tuple contains all pre-defined translation contexts", /* doc */
- app_translations_contexts_fields, /* fields */
+ "bpy.app.translations.contexts", /* name */
+ "This named tuple contains all predefined translation contexts", /* doc */
+ app_translations_contexts_fields, /* fields */
ARRAY_SIZE(app_translations_contexts_fields) - 1,
};
@@ -464,7 +464,7 @@ static PyObject *app_translations_contexts_make(void)
* \{ */
PyDoc_STRVAR(app_translations_contexts_doc,
- "A named tuple containing all pre-defined translation contexts.\n"
+ "A named tuple containing all predefined translation contexts.\n"
"\n"
".. warning::\n"
" Never use a (new) context starting with \"" BLT_I18NCONTEXT_DEFAULT_BPYRNA
@@ -794,10 +794,14 @@ static PyTypeObject BlenderAppTranslationsType = {
0, /* tp_itemsize */
/* methods */
/* No destructor, this is a singleton! */
- NULL, /* tp_dealloc */
- (printfunc)NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_dealloc */
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall_offset */
+#else
+ (printfunc)NULL, /* printfunc tp_print */
+#endif
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in python 3.0! */
NULL, /* tp_repr */
@@ -896,7 +900,7 @@ PyObject *BPY_app_translations_struct(void)
/* prevent user from creating new instances */
BlenderAppTranslationsType.tp_new = NULL;
- /* without this we can't do set(sys.modules) [#29635] */
+ /* without this we can't do set(sys.modules) T29635. */
BlenderAppTranslationsType.tp_hash = (hashfunc)_Py_HashPointer;
return ret;
diff --git a/source/blender/python/intern/bpy_app_usd.c b/source/blender/python/intern/bpy_app_usd.c
index d60264ef259..4a0ee96061a 100644
--- a/source/blender/python/intern/bpy_app_usd.c
+++ b/source/blender/python/intern/bpy_app_usd.c
@@ -101,7 +101,7 @@ PyObject *BPY_app_usd_struct(void)
BlenderAppUSDType.tp_init = NULL;
BlenderAppUSDType.tp_new = NULL;
BlenderAppUSDType.tp_hash = (hashfunc)
- _Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+ _Py_HashPointer; /* without this we can't do set(sys.modules) T29635. */
return ret;
}
diff --git a/source/blender/python/intern/bpy_capi_utils.c b/source/blender/python/intern/bpy_capi_utils.c
index 8eb44e918d7..57dc4c0a679 100644
--- a/source/blender/python/intern/bpy_capi_utils.c
+++ b/source/blender/python/intern/bpy_capi_utils.c
@@ -38,16 +38,6 @@
#include "../generic/py_capi_utils.h"
-static bContext *__py_context = NULL;
-bContext *BPy_GetContext(void)
-{
- return __py_context;
-}
-void BPy_SetContext(bContext *C)
-{
- __py_context = C;
-}
-
char *BPy_enum_as_string(const EnumPropertyItem *item)
{
DynStr *dynstr = BLI_dynstr_new();
diff --git a/source/blender/python/intern/bpy_capi_utils.h b/source/blender/python/intern/bpy_capi_utils.h
index 861b23190a2..55f8a291410 100644
--- a/source/blender/python/intern/bpy_capi_utils.h
+++ b/source/blender/python/intern/bpy_capi_utils.h
@@ -48,9 +48,7 @@ bool BPy_errors_to_report_ex(struct ReportList *reports,
bool BPy_errors_to_report_brief_with_prefix(struct ReportList *reports, const char *error_prefix);
bool BPy_errors_to_report(struct ReportList *reports);
-/* TODO - find a better solution! */
-struct bContext *BPy_GetContext(void);
-void BPy_SetContext(struct bContext *C);
+struct bContext *BPY_context_get(void);
extern void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate);
extern void bpy_context_clear(struct bContext *C, const PyGILState_STATE *gilstate);
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index 4ef685b7987..c0536693f38 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -266,7 +266,7 @@ static void pydriver_error(ChannelDriver *driver)
"\nError in Driver: The following Python expression failed:\n\t'%s'\n\n",
driver->expression);
- // BPy_errors_to_report(NULL); // TODO - reports
+ // BPy_errors_to_report(NULL); /* TODO - reports */
PyErr_Print();
PyErr_Clear();
}
@@ -494,7 +494,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
}
/* needed since drivers are updated directly after undo where 'main' is
- * re-allocated [#28807] */
+ * re-allocated T28807. */
BPY_update_rna_module();
/* init global dictionary for py-driver evaluation settings */
@@ -613,7 +613,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
fprintf(
stderr, "\tBPY_driver_eval() - couldn't add variable '%s' to namespace\n", dvar->name);
- // BPy_errors_to_report(NULL); // TODO - reports
+ // BPy_errors_to_report(NULL); /* TODO - reports */
PyErr_Print();
PyErr_Clear();
}
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index bc7318e1a15..0b11ac639c7 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -80,6 +80,7 @@
/* Logging types to use anywhere in the Python modules. */
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_CONTEXT, "bpy.context");
+CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_INTERFACE, "bpy.interface");
CLG_LOGREF_DECLARE_GLOBAL(BPY_LOG_RNA, "bpy.rna");
/* for internal use, when starting and ending python scripts */
@@ -91,7 +92,7 @@ static int py_call_level = 0;
/* Set by command line arguments before Python starts. */
static bool py_use_system_env = false;
-// #define TIME_PY_RUN // simple python tests. prints on exit.
+// #define TIME_PY_RUN /* simple python tests. prints on exit. */
#ifdef TIME_PY_RUN
# include "PIL_time.h"
@@ -111,8 +112,8 @@ void BPY_context_update(bContext *C)
return;
}
- BPy_SetContext(C);
- BPY_modules_update(C); /* can give really bad results if this isn't here */
+ BPY_context_set(C);
+ BPY_modules_update(); /* can give really bad results if this isn't here */
}
void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
@@ -155,7 +156,7 @@ void bpy_context_clear(bContext *UNUSED(C), const PyGILState_STATE *gilstate)
/* XXX - Calling classes currently wont store the context :\,
* cant set NULL because of this. but this is very flakey still. */
#if 0
- BPy_SetContext(NULL);
+ BPY_context_set(NULL);
#endif
#ifdef TIME_PY_RUN
@@ -165,6 +166,46 @@ void bpy_context_clear(bContext *UNUSED(C), const PyGILState_STATE *gilstate)
}
}
+/**
+ * Use for `CTX_*_set(..)` functions need to set values which are later read back as expected.
+ * In this case we don't want the Python context to override the values as it causes problems
+ * see T66256.
+ *
+ * \param dict_p: A pointer to #bContext.data.py_context so we can assign a new value.
+ * \param dict_orig: The value of #bContext.data.py_context_orig to check if we need to copy.
+ *
+ * \note Typically accessed via #BPY_context_dict_clear_members macro.
+ */
+void BPY_context_dict_clear_members_array(void **dict_p,
+ void *dict_orig,
+ const char *context_members[],
+ uint context_members_len)
+{
+ PyGILState_STATE gilstate;
+ const bool use_gil = !PyC_IsInterpreterActive();
+
+ if (use_gil) {
+ gilstate = PyGILState_Ensure();
+ }
+
+ /* Copy on write. */
+ if (*dict_p == dict_orig) {
+ *dict_p = PyDict_Copy(dict_orig);
+ }
+
+ PyObject *dict = *dict_p;
+ BLI_assert(PyDict_Check(dict));
+ for (uint i = 0; i < context_members_len; i++) {
+ if (PyDict_DelItemString(dict, context_members[i])) {
+ PyErr_Clear();
+ }
+ }
+
+ if (use_gil) {
+ PyGILState_Release(gilstate);
+ }
+}
+
void BPY_text_free_code(Text *text)
{
if (text->compiled) {
@@ -184,7 +225,10 @@ void BPY_text_free_code(Text *text)
}
}
-void BPY_modules_update(bContext *C)
+/**
+ * Needed so the #Main pointer in `bpy.data` doesn't become out of date.
+ */
+void BPY_modules_update(void)
{
#if 0 /* slow, this runs all the time poll, draw etc 100's of time a sec. */
PyObject *mod = PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
@@ -194,14 +238,16 @@ void BPY_modules_update(bContext *C)
/* refreshes the main struct */
BPY_update_rna_module();
- if (bpy_context_module) {
- bpy_context_module->ptr.data = (void *)C;
- }
+}
+
+bContext *BPY_context_get(void)
+{
+ return bpy_context_module->ptr.data;
}
void BPY_context_set(bContext *C)
{
- BPy_SetContext(C);
+ bpy_context_module->ptr.data = (void *)C;
}
#ifdef WITH_FLUID
@@ -255,13 +301,16 @@ static struct _inittab bpy_internal_modules[] = {
};
/* call BPY_context_set first */
-void BPY_python_start(int argc, const char **argv)
+void BPY_python_start(bContext *C, int argc, const char **argv)
{
#ifndef WITH_PYTHON_MODULE
PyThreadState *py_tstate = NULL;
- const char *py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, NULL);
- /* Not essential but nice to set our name. */
+ /* Needed for Python's initialization for portable Python installations.
+ * We could use #Py_SetPath, but this overrides Python's internal logic
+ * for calculating it's own module search paths.
+ *
+ * `sys.executable` is overwritten after initialization to the Python binary. */
{
const char *program_path = BKE_appdir_program_path();
wchar_t program_path_wchar[FILE_MAX];
@@ -272,8 +321,21 @@ void BPY_python_start(int argc, const char **argv)
/* must run before python initializes */
PyImport_ExtendInittab(bpy_internal_modules);
- /* allow to use our own included python */
- PyC_SetHomePath(py_path_bundle);
+ /* Allow to use our own included Python. `py_path_bundle` may be NULL. */
+ {
+ const char *py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, NULL);
+ if (py_path_bundle != NULL) {
+ PyC_SetHomePath(py_path_bundle);
+ }
+ else {
+ /* Common enough to use the system Python on Linux/Unix, warn on other systems. */
+# if defined(__APPLE__) || defined(_WIN32)
+ fprintf(stderr,
+ "Bundled Python not found and is expected on this platform "
+ "(the 'install' target may have not been built)\n");
+# endif
+ }
+ }
/* Without this the `sys.stdout` may be set to 'ascii'
* (it is on my system at least), where printing unicode values will raise
@@ -291,25 +353,41 @@ void BPY_python_start(int argc, const char **argv)
Py_IgnoreEnvironmentFlag = !py_use_system_env;
Py_NoUserSiteDirectory = !py_use_system_env;
+ /* Initialize Python (also acquires lock). */
Py_Initialize();
- // PySys_SetArgv(argc, argv); /* broken in py3, not a huge deal */
- /* sigh, why do python guys not have a (char **) version anymore? */
+ /* We could convert to #wchar_t then pass to #PySys_SetArgv (or use #PyConfig in Python 3.8+).
+ * However this risks introducing subtle changes in encoding that are hard to track down.
+ *
+ * So rely on #PyC_UnicodeFromByte since it's a tried & true way of getting paths
+ * that include non `utf-8` compatible characters, see: T20021. */
{
- int i;
PyObject *py_argv = PyList_New(argc);
- for (i = 0; i < argc; i++) {
- /* should fix bug #20021 - utf path name problems, by replacing
- * PyUnicode_FromString, with this one */
+ for (int i = 0; i < argc; i++) {
PyList_SET_ITEM(py_argv, i, PyC_UnicodeFromByte(argv[i]));
}
-
PySys_SetObject("argv", py_argv);
Py_DECREF(py_argv);
}
- /* Initialize thread support (also acquires lock) */
- PyEval_InitThreads();
+ /* Setting the program name is important so the 'multiprocessing' module
+ * can launch new Python instances. */
+ {
+ const char *sys_variable = "executable";
+ char program_path[FILE_MAX];
+ if (BKE_appdir_program_python_search(
+ program_path, sizeof(program_path), PY_MAJOR_VERSION, PY_MINOR_VERSION)) {
+ PyObject *py_program_path = PyC_UnicodeFromByte(program_path);
+ PySys_SetObject(sys_variable, py_program_path);
+ Py_DECREF(py_program_path);
+ }
+ else {
+ fprintf(stderr,
+ "Unable to find the python binary, "
+ "the multiprocessing module may not be functional!\n");
+ PySys_SetObject(sys_variable, Py_None);
+ }
+ }
# ifdef WITH_FLUID
/* Required to prevent assertion error, see:
@@ -349,7 +427,7 @@ void BPY_python_start(int argc, const char **argv)
#endif
/* bpy.* and lets us import it */
- BPy_init_modules();
+ BPy_init_modules(C);
pyrna_alloc_types();
@@ -627,7 +705,7 @@ static void bpy_module_delay_init(PyObject *bpy_proxy)
const int argc = 1;
const char *argv[2];
- /* updating the module dict below will loose the reference to __file__ */
+ /* updating the module dict below will lose the reference to __file__ */
PyObject *filename_obj = PyModule_GetFilenameObject(bpy_proxy);
const char *filename_rel = _PyUnicode_AsString(filename_obj); /* can be relative */
diff --git a/source/blender/python/intern/bpy_interface_atexit.c b/source/blender/python/intern/bpy_interface_atexit.c
index e69914671dd..8e5a6dc530b 100644
--- a/source/blender/python/intern/bpy_interface_atexit.c
+++ b/source/blender/python/intern/bpy_interface_atexit.c
@@ -34,7 +34,7 @@
static PyObject *bpy_atexit(PyObject *UNUSED(self), PyObject *UNUSED(args), PyObject *UNUSED(kw))
{
/* close down enough of blender at least not to crash */
- struct bContext *C = BPy_GetContext();
+ struct bContext *C = BPY_context_get();
WM_exit_ex(C, false);
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index a3750d348f5..bc3d8b2c360 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -92,9 +92,13 @@ static PyTypeObject bpy_lib_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)bpy_lib_dealloc, /* tp_dealloc */
- (printfunc)NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall_offset */
+#else
+ (printfunc)NULL, /* printfunc tp_print */
+#endif
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in python 3.0! */
NULL, /* tp_repr */
@@ -180,7 +184,7 @@ PyDoc_STRVAR(
" :type relative: bool\n");
static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
{
- Main *bmain = CTX_data_main(BPy_GetContext());
+ Main *bmain = CTX_data_main(BPY_context_get());
BPy_Library *ret;
const char *filename = NULL;
bool is_rel = false, is_link = false;
@@ -319,7 +323,7 @@ static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item)
static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
{
- Main *bmain = CTX_data_main(BPy_GetContext());
+ Main *bmain = CTX_data_main(BPY_context_get());
Main *mainl = NULL;
const int err = 0;
const bool do_append = ((self->flag & FILE_LINK) == 0);
diff --git a/source/blender/python/intern/bpy_msgbus.c b/source/blender/python/intern/bpy_msgbus.c
index 3739f56dc79..df45007b68f 100644
--- a/source/blender/python/intern/bpy_msgbus.c
+++ b/source/blender/python/intern/bpy_msgbus.c
@@ -265,7 +265,7 @@ static PyObject *bpy_msgbus_subscribe_rna(PyObject *UNUSED(self), PyObject *args
}
/* Note: we may want to have a way to pass this in. */
- bContext *C = (bContext *)BPy_GetContext();
+ bContext *C = BPY_context_get();
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
wmMsgParams_RNA msg_key_params = {{0}};
@@ -340,7 +340,7 @@ static PyObject *bpy_msgbus_publish_rna(PyObject *UNUSED(self), PyObject *args,
}
/* Note: we may want to have a way to pass this in. */
- bContext *C = (bContext *)BPy_GetContext();
+ bContext *C = BPY_context_get();
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
wmMsgParams_RNA msg_key_params = {{0}};
@@ -359,7 +359,7 @@ PyDoc_STRVAR(bpy_msgbus_clear_by_owner_doc,
" Clear all subscribers using this owner.\n");
static PyObject *bpy_msgbus_clear_by_owner(PyObject *UNUSED(self), PyObject *py_owner)
{
- bContext *C = (bContext *)BPy_GetContext();
+ bContext *C = BPY_context_get();
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
WM_msgbus_clear_by_owner(mbus, py_owner);
Py_RETURN_NONE;
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index 6d86d788644..5ac76ab9ac1 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -77,7 +77,6 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
wmOperatorType *ot;
const char *opname;
PyObject *context_dict = NULL; /* optional args */
- PyObject *context_dict_back;
const char *context_str = NULL;
PyObject *ret;
@@ -85,7 +84,7 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
/* XXX Todo, work out a better solution for passing on context,
* could make a tuple from self and pack the name and Context into it... */
- bContext *C = (bContext *)BPy_GetContext();
+ bContext *C = BPY_context_get();
if (C == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators");
@@ -119,7 +118,7 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
}
}
- if (context_dict == NULL || context_dict == Py_None) {
+ if (ELEM(context_dict, NULL, Py_None)) {
context_dict = NULL;
}
else if (!PyDict_Check(context_dict)) {
@@ -131,16 +130,25 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
return NULL;
}
- context_dict_back = CTX_py_dict_get(C);
- CTX_py_dict_set(C, (void *)context_dict);
- Py_XINCREF(context_dict); /* so we done loose it */
+ struct bContext_PyState context_py_state;
+ if (context_dict != NULL) {
+ CTX_py_state_push(C, &context_py_state, (void *)context_dict);
+ Py_INCREF(context_dict); /* so we don't lose it */
+ }
/* main purpose of this function */
ret = WM_operator_poll_context((bContext *)C, ot, context) ? Py_True : Py_False;
- /* restore with original context dict, probably NULL but need this for nested operator calls */
- Py_XDECREF(context_dict);
- CTX_py_dict_set(C, (void *)context_dict_back);
+ if (context_dict != NULL) {
+ PyObject *context_dict_test = CTX_py_dict_get(C);
+ if (context_dict_test != context_dict) {
+ Py_DECREF(context_dict_test);
+ }
+ /* Restore with original context dict,
+ * probably NULL but need this for nested operator calls. */
+ Py_DECREF(context_dict);
+ CTX_py_state_pop(C, &context_py_state);
+ }
return Py_INCREF_RET(ret);
}
@@ -156,7 +164,6 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
const char *context_str = NULL;
PyObject *kw = NULL; /* optional args */
PyObject *context_dict = NULL; /* optional args */
- PyObject *context_dict_back;
/* note that context is an int, python does the conversion in this case */
int context = WM_OP_EXEC_DEFAULT;
@@ -164,7 +171,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
/* XXX Todo, work out a better solution for passing on context,
* could make a tuple from self and pack the name and Context into it... */
- bContext *C = (bContext *)BPy_GetContext();
+ bContext *C = BPY_context_get();
if (C == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Context is None, cant poll any operators");
@@ -213,7 +220,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
}
}
- if (context_dict == NULL || context_dict == Py_None) {
+ if (ELEM(context_dict, NULL, Py_None)) {
context_dict = NULL;
}
else if (!PyDict_Check(context_dict)) {
@@ -225,17 +232,16 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
return NULL;
}
- context_dict_back = CTX_py_dict_get(C);
-
/**
* It might be that there is already a Python context override. We don't want to remove that
* except when this operator call sets a new override explicitly. This is necessary so that
* called operator runs in the same context as the calling code by default.
*/
+ struct bContext_PyState context_py_state;
if (context_dict != NULL) {
- CTX_py_dict_set(C, (void *)context_dict);
+ CTX_py_state_push(C, &context_py_state, (void *)context_dict);
+ Py_INCREF(context_dict); /* so we don't lose it */
}
- Py_XINCREF(context_dict); /* so we done loose it */
if (WM_operator_poll_context((bContext *)C, ot, context) == false) {
const char *msg = CTX_wm_operator_poll_msg_get(C);
@@ -314,9 +320,16 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
#endif
}
- /* restore with original context dict, probably NULL but need this for nested operator calls */
- Py_XDECREF(context_dict);
- CTX_py_dict_set(C, (void *)context_dict_back);
+ if (context_dict != NULL) {
+ PyObject *context_dict_test = CTX_py_dict_get(C);
+ if (context_dict_test != context_dict) {
+ Py_DECREF(context_dict_test);
+ }
+ /* Restore with original context dict,
+ * probably NULL but need this for nested operator calls. */
+ Py_DECREF(context_dict);
+ CTX_py_state_pop(C, &context_py_state);
+ }
if (error_val == -1) {
return NULL;
@@ -326,7 +339,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
* is freed by clear_globals(), further access will crash blender.
* Setting context is not needed in this case, only calling because this
* function corrects bpy.data (internal Main pointer) */
- BPY_modules_update(C);
+ BPY_modules_update();
/* return operator_ret as a bpy enum */
return pyrna_enum_bitfield_to_py(rna_enum_operator_return_items, operator_ret);
@@ -346,7 +359,7 @@ static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args)
char *buf = NULL;
PyObject *pybuf;
- bContext *C = (bContext *)BPy_GetContext();
+ bContext *C = BPY_context_get();
if (C == NULL) {
PyErr_SetString(PyExc_RuntimeError,
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index bc708bd4a89..d45c8e8b131 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -112,17 +112,21 @@ static const EnumPropertyItem property_flag_override_collection_items[] = {
0,
"No Name",
"Do not use the names of the items, only their indices in the collection"},
+ {PROPOVERRIDE_LIBRARY_INSERTION,
+ "USE_INSERTION",
+ 0,
+ "Use Insertion",
+ "Allow users to add new items in that collection in library overrides"},
{0, NULL, 0, NULL, NULL},
};
#define BPY_PROPDEF_OPTIONS_OVERRIDE_COLLECTION_DOC \
- " :arg override: Enumerator in ['LIBRARY_OVERRIDABLE', 'NO_PROPERTY_NAME'].\n" \
+ " :arg override: Enumerator in ['LIBRARY_OVERRIDABLE', 'NO_PROPERTY_NAME', " \
+ "'USE_INSERTION'].\n" \
" :type override: set\n"
/* subtypes */
-/* XXX Keep in sync with rna_rna.c's rna_enum_property_subtype_items ???
- * Currently it is not...
- */
+/* Keep in sync with RNA_types.h PropertySubType and rna_rna.c's rna_enum_property_subtype_items */
static const EnumPropertyItem property_subtype_string_items[] = {
{PROP_FILEPATH, "FILE_PATH", 0, "File Path", ""},
{PROP_DIRPATH, "DIR_PATH", 0, "Directory Path", ""},
@@ -147,6 +151,9 @@ static const EnumPropertyItem property_subtype_number_items[] = {
{PROP_ANGLE, "ANGLE", 0, "Angle", ""},
{PROP_TIME, "TIME", 0, "Time", ""},
{PROP_DISTANCE, "DISTANCE", 0, "Distance", ""},
+ {PROP_DISTANCE_CAMERA, "DISTANCE_CAMERA", 0, "Camera Distance", ""},
+ {PROP_POWER, "POWER", 0, "Power", ""},
+ {PROP_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""},
{PROP_NONE, "NONE", 0, "None", ""},
{0, NULL, 0, NULL, NULL},
@@ -154,7 +161,7 @@ static const EnumPropertyItem property_subtype_number_items[] = {
#define BPY_PROPDEF_SUBTYPE_NUMBER_DOC \
" :arg subtype: Enumerator in ['PIXEL', 'UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', " \
- "'TIME', 'DISTANCE', 'NONE'].\n" \
+ "'TIME', 'DISTANCE', 'DISTANCE_CAMERA', 'POWER', 'TEMPERATURE', 'NONE'].\n" \
" :type subtype: string\n"
static const EnumPropertyItem property_subtype_array_items[] = {
@@ -168,11 +175,11 @@ static const EnumPropertyItem property_subtype_array_items[] = {
{PROP_QUATERNION, "QUATERNION", 0, "Quaternion", ""},
{PROP_AXISANGLE, "AXISANGLE", 0, "Axis Angle", ""},
{PROP_XYZ, "XYZ", 0, "XYZ", ""},
+ {PROP_XYZ_LENGTH, "XYZ_LENGTH", 0, "XYZ Length", ""},
{PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Color Gamma", ""},
+ {PROP_COORDS, "COORDINATES", 0, "Vector Coordinates", ""},
{PROP_LAYER, "LAYER", 0, "Layer", ""},
{PROP_LAYER_MEMBER, "LAYER_MEMBER", 0, "Layer Member", ""},
- {PROP_POWER, "POWER", 0, "Power", ""},
- {PROP_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""},
{PROP_NONE, "NONE", 0, "None", ""},
{0, NULL, 0, NULL, NULL},
@@ -181,7 +188,7 @@ static const EnumPropertyItem property_subtype_array_items[] = {
#define BPY_PROPDEF_SUBTYPE_ARRAY_DOC \
" :arg subtype: Enumerator in ['COLOR', 'TRANSLATION', 'DIRECTION', " \
"'VELOCITY', 'ACCELERATION', 'MATRIX', 'EULER', 'QUATERNION', 'AXISANGLE', " \
- "'XYZ', 'COLOR_GAMMA', 'LAYER', 'LAYER_MEMBER', 'POWER', 'NONE'].\n" \
+ "'XYZ', 'XYZ_LENGTH', 'COLOR_GAMMA', 'COORDINATES', 'LAYER', 'LAYER_MEMBER', 'NONE'].\n" \
" :type subtype: string\n"
/* PyObject's */
@@ -1986,8 +1993,9 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop,
} \
srna = srna_from_self(self, #_func "(...):"); \
if (srna == NULL) { \
- if (PyErr_Occurred()) \
+ if (PyErr_Occurred()) { \
return NULL; \
+ } \
return bpy_prop_deferred_return(pymeth_##_func, kw); \
} \
(void)0
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 0980d9df762..6e41bc96eed 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -80,6 +80,11 @@
#define USE_MATHUTILS
#define USE_STRING_COERCE
+/* Unfortunately Python needs to hold a global reference to the context.
+ * If we remove this is means `bpy.context` won't be usable from some parts of the code:
+ * `bpy.app.handler` callbacks for example.
+ * Even though this is arguably "correct", it's going to cause problems for existing scripts,
+ * so accept having this for the time being. */
BPy_StructRNA *bpy_context_module = NULL; /* for fast access */
static PyObject *pyrna_struct_Subtype(PointerRNA *ptr);
@@ -457,7 +462,7 @@ static int mathutils_rna_vector_set(BaseMathObject *bmo, int subtype)
RNA_property_float_set_array(&self->ptr, self->prop, bmo->data);
if (RNA_property_update_check(self->prop)) {
- RNA_property_update(BPy_GetContext(), &self->ptr, self->prop);
+ RNA_property_update(BPY_context_get(), &self->ptr, self->prop);
}
/* Euler order exception. */
@@ -468,7 +473,7 @@ static int mathutils_rna_vector_set(BaseMathObject *bmo, int subtype)
if (order != eul->order) {
RNA_property_enum_set(&self->ptr, prop_eul_order, eul->order);
if (RNA_property_update_check(prop_eul_order)) {
- RNA_property_update(BPy_GetContext(), &self->ptr, prop_eul_order);
+ RNA_property_update(BPY_context_get(), &self->ptr, prop_eul_order);
}
}
}
@@ -517,7 +522,7 @@ static int mathutils_rna_vector_set_index(BaseMathObject *bmo, int UNUSED(subtyp
RNA_property_float_set_index(&self->ptr, self->prop, index, bmo->data[index]);
if (RNA_property_update_check(self->prop)) {
- RNA_property_update(BPy_GetContext(), &self->ptr, self->prop);
+ RNA_property_update(BPY_context_get(), &self->ptr, self->prop);
}
return 0;
@@ -576,7 +581,7 @@ static int mathutils_rna_matrix_set(BaseMathObject *bmo, int UNUSED(subtype))
RNA_property_float_set_array(&self->ptr, self->prop, bmo->data);
if (RNA_property_update_check(self->prop)) {
- RNA_property_update(BPy_GetContext(), &self->ptr, self->prop);
+ RNA_property_update(BPY_context_get(), &self->ptr, self->prop);
}
return 0;
}
@@ -722,7 +727,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
}
else {
/* Order will be updated from callback on use. */
- // TODO, get order from RNA
+ /* TODO, get order from RNA. */
PyObject *eul_cb = Euler_CreatePyObject_cb(
ret, EULER_ORDER_XYZ, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_EUL);
Py_DECREF(ret); /* The euler owns 'ret' now. */
@@ -890,22 +895,36 @@ static PyObject *pyrna_struct_str(BPy_StructRNA *self)
{
PyObject *ret;
const char *name;
+ const char *extra_info = "";
if (!PYRNA_STRUCT_IS_VALID(self)) {
return PyUnicode_FromFormat("<bpy_struct, %.200s invalid>", Py_TYPE(self)->tp_name);
}
- /* Print name if available. */
+ ID *id = self->ptr.owner_id;
+ if (id && id != DEG_get_original_id(id)) {
+ extra_info = ", evaluated";
+ }
+
+ /* Print name if available.
+ *
+ * Always include the pointer address since it can help identify unique data,
+ * or when data is re-allocated internally. */
name = RNA_struct_name_get_alloc(&self->ptr, NULL, 0, NULL);
if (name) {
- ret = PyUnicode_FromFormat(
- "<bpy_struct, %.200s(\"%.200s\")>", RNA_struct_identifier(self->ptr.type), name);
+ ret = PyUnicode_FromFormat("<bpy_struct, %.200s(\"%.200s\") at %p%s>",
+ RNA_struct_identifier(self->ptr.type),
+ name,
+ self->ptr.data,
+ extra_info);
MEM_freeN((void *)name);
return ret;
}
- return PyUnicode_FromFormat(
- "<bpy_struct, %.200s at %p>", RNA_struct_identifier(self->ptr.type), self->ptr.data);
+ return PyUnicode_FromFormat("<bpy_struct, %.200s at %p%s>",
+ RNA_struct_identifier(self->ptr.type),
+ self->ptr.data,
+ extra_info);
}
static PyObject *pyrna_struct_repr(BPy_StructRNA *self)
@@ -914,18 +933,14 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self)
PyObject *tmp_str;
PyObject *ret;
- if (id == NULL || !PYRNA_STRUCT_IS_VALID(self)) {
+ if (id == NULL || !PYRNA_STRUCT_IS_VALID(self) || (DEG_get_original_id(id) != id)) {
/* fallback */
return pyrna_struct_str(self);
}
tmp_str = PyUnicode_FromString(id->name + 2);
- if (DEG_get_original_id(id) != id) {
- ret = PyUnicode_FromFormat(
- "Evaluated %s %R", BKE_idtype_idcode_to_name(GS(id->name)), tmp_str);
- }
- else if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_EMBEDDED_DATA) == 0) {
+ if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_EMBEDDED_DATA) == 0) {
ret = PyUnicode_FromFormat(
"bpy.data.%s[%R]", BKE_idtype_idcode_to_name_plural(GS(id->name)), tmp_str);
}
@@ -1219,7 +1234,7 @@ static const char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop)
const char *result;
bool free = false;
- RNA_property_enum_items(BPy_GetContext(), ptr, prop, &item, NULL, &free);
+ RNA_property_enum_items(BPY_context_get(), ptr, prop, &item, NULL, &free);
if (item) {
result = BPy_enum_as_string(item);
}
@@ -1247,7 +1262,7 @@ static int pyrna_string_to_enum(
return -1;
}
- if (!RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, r_value)) {
+ if (!RNA_property_enum_value(BPY_context_get(), ptr, prop, param, r_value)) {
const char *enum_str = pyrna_enum_as_string(ptr, prop);
PyErr_Format(PyExc_TypeError,
"%.200s enum \"%.200s\" not found in (%s)",
@@ -1389,7 +1404,7 @@ static int pyrna_prop_to_enum_bitfield(
return -1;
}
- RNA_property_enum_items(BPy_GetContext(), ptr, prop, &item, NULL, &free);
+ RNA_property_enum_items(BPY_context_get(), ptr, prop, &item, NULL, &free);
if (item) {
ret = pyrna_set_to_enum_bitfield(item, value, r_value, error_prefix);
@@ -1441,7 +1456,7 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
ret = PySet_New(NULL);
- if (RNA_property_enum_bitflag_identifiers(BPy_GetContext(), ptr, prop, val, identifier)) {
+ if (RNA_property_enum_bitflag_identifiers(BPY_context_get(), ptr, prop, val, identifier)) {
int index;
for (index = 0; identifier[index]; index++) {
@@ -1453,7 +1468,7 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
}
else {
const char *identifier;
- if (RNA_property_enum_identifier(BPy_GetContext(), ptr, prop, val, &identifier)) {
+ if (RNA_property_enum_identifier(BPY_context_get(), ptr, prop, val, &identifier)) {
ret = PyUnicode_FromString(identifier);
}
else {
@@ -2202,7 +2217,7 @@ static int pyrna_py_to_prop(
/* Run RNA property functions. */
if (RNA_property_update_check(prop)) {
- RNA_property_update(BPy_GetContext(), ptr, prop);
+ RNA_property_update(BPY_context_get(), ptr, prop);
}
return 0;
@@ -2278,7 +2293,7 @@ static int pyrna_py_to_prop_array_index(BPy_PropertyArrayRNA *self, int index, P
/* Run RNA property functions. */
if (RNA_property_update_check(prop)) {
- RNA_property_update(BPy_GetContext(), ptr, prop);
+ RNA_property_update(BPY_context_get(), ptr, prop);
}
return ret;
@@ -3282,7 +3297,7 @@ static int pyrna_prop_array_ass_subscript(BPy_PropertyArrayRNA *self,
if (ret != -1) {
if (RNA_property_update_check(self->prop)) {
- RNA_property_update(BPy_GetContext(), &self->ptr, self->prop);
+ RNA_property_update(BPY_context_get(), &self->ptr, self->prop);
}
}
@@ -3589,20 +3604,30 @@ static PyObject *pyrna_struct_values(BPy_PropertyRNA *self)
}
PyDoc_STRVAR(pyrna_struct_is_property_set_doc,
- ".. method:: is_property_set(property)\n"
+ ".. method:: is_property_set(property, ghost=True)\n"
"\n"
" Check if a property is set, use for testing operator properties.\n"
"\n"
+ " :arg ghost: Used for operators that re-run with previous settings.\n"
+ " In this case the property is not marked as set,\n"
+ " yet the value from the previous execution is used.\n"
+ "\n"
+ " In rare cases you may want to set this option to false.\n"
+ "\n"
+ " :type ghost: boolean\n"
" :return: True when the property has been set.\n"
" :rtype: boolean\n");
-static PyObject *pyrna_struct_is_property_set(BPy_StructRNA *self, PyObject *args)
+static PyObject *pyrna_struct_is_property_set(BPy_StructRNA *self, PyObject *args, PyObject *kw)
{
PropertyRNA *prop;
const char *name;
+ bool use_ghost = true;
PYRNA_STRUCT_CHECK_OBJ(self);
- if (!PyArg_ParseTuple(args, "s:is_property_set", &name)) {
+ static const char *_keywords[] = {"", "ghost", NULL};
+ static _PyArg_Parser _parser = {"s|$O&:is_property_set", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &name, PyC_ParseBool, &use_ghost)) {
return NULL;
}
@@ -3614,7 +3639,7 @@ static PyObject *pyrna_struct_is_property_set(BPy_StructRNA *self, PyObject *arg
return NULL;
}
- return PyBool_FromLong(RNA_property_is_set(&self->ptr, prop));
+ return PyBool_FromLong(RNA_property_is_set_ex(&self->ptr, prop, use_ghost));
}
PyDoc_STRVAR(pyrna_struct_property_unset_doc,
@@ -3952,7 +3977,7 @@ PyDoc_STRVAR(pyrna_prop_update_doc,
" however in rare cases it's useful to call explicitly.\n");
static PyObject *pyrna_prop_update(BPy_PropertyRNA *self)
{
- RNA_property_update(BPy_GetContext(), &self->ptr, self->prop);
+ RNA_property_update(BPY_context_get(), &self->ptr, self->prop);
Py_RETURN_NONE;
}
@@ -4250,9 +4275,9 @@ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname)
ListBase newlb;
short newtype;
- const int done = CTX_data_get(C, name, &newptr, &newlb, &newtype);
+ const eContextResult done = CTX_data_get(C, name, &newptr, &newlb, &newtype);
- if (done == 1) { /* Found. */
+ if (done == CTX_RESULT_OK) {
switch (newtype) {
case CTX_DATA_TYPE_POINTER:
if (newptr.data == NULL) {
@@ -4285,7 +4310,7 @@ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname)
break;
}
}
- else if (done == -1) { /* Found, but not set. */
+ else if (done == CTX_RESULT_NO_DATA) {
ret = Py_None;
Py_INCREF(ret);
}
@@ -4472,9 +4497,9 @@ static int pyrna_struct_setattro(BPy_StructRNA *self, PyObject *pyname, PyObject
ListBase newlb;
short newtype;
- const int done = CTX_data_get(C, name, &newptr, &newlb, &newtype);
+ const eContextResult done = CTX_data_get(C, name, &newptr, &newlb, &newtype);
- if (done == 1) {
+ if (done == CTX_RESULT_OK) {
PyErr_Format(
PyExc_AttributeError, "bpy_struct: Context property \"%.200s\" is read-only", name);
BLI_freelistN(&newlb);
@@ -4829,7 +4854,7 @@ static PyObject *pyrna_prop_collection_items(BPy_PropertyRNA *self)
}
}
else {
- /* A bit strange, but better then returning an empty list. */
+ /* A bit strange, but better than returning an empty list. */
PyTuple_SET_ITEM(item, 0, PyLong_FromLong(i));
}
PyTuple_SET_ITEM(item, 1, pyrna_struct_CreatePyObject(&itemptr));
@@ -5406,7 +5431,7 @@ static PyObject *pyprop_array_foreach_getset(BPy_PropertyArrayRNA *self,
/* Get/set both take the same args currently. */
PyObject *seq;
- if (prop_type != PROP_INT && prop_type != PROP_FLOAT) {
+ if (!ELEM(prop_type, PROP_INT, PROP_FLOAT)) {
PyErr_Format(PyExc_TypeError, "foreach_get/set available only for int and float");
return NULL;
}
@@ -5639,7 +5664,7 @@ static struct PyMethodDef pyrna_struct_methods[] = {
{"is_property_set",
(PyCFunction)pyrna_struct_is_property_set,
- METH_VARARGS,
+ METH_VARARGS | METH_KEYWORDS,
pyrna_struct_is_property_set_doc},
{"property_unset",
(PyCFunction)pyrna_struct_property_unset,
@@ -5845,7 +5870,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat
/* Resolve the array from a new pytype. */
- /* TODO(Kazanbas) make multi-dimensional sequences here. */
+ /* TODO(Kazanbas): make multi-dimensional sequences here. */
switch (type) {
case PROP_BOOLEAN:
@@ -6038,7 +6063,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
/* enable this so all strings are copied and freed after calling.
* this exposes bugs where the pointer to the string is held and re-used */
- // #define DEBUG_STRING_FREE
+ /* #define DEBUG_STRING_FREE */
#ifdef DEBUG_STRING_FREE
PyObject *string_free_ls = PyList_New(0);
@@ -6204,7 +6229,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
/* Check if we gave args that don't exist in the function
* Printing the error is slow, but it should only happen when developing.
- * The "if" below is quick check to make sure less keyword args were passed then we gave.
+ * The "if" below is quick check to make sure less keyword args were passed than we gave.
* (Don't overwrite the error if we have one,
* otherwise can skip important messages and confuse with args).
*/
@@ -6284,7 +6309,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject
if (err == 0) {
/* Call function. */
ReportList reports;
- bContext *C = BPy_GetContext();
+ bContext *C = BPY_context_get();
BKE_reports_init(&reports, RPT_STORE);
RNA_function_call(C, &reports, self_ptr, self_func, &parms);
@@ -6378,10 +6403,14 @@ PyTypeObject pyrna_struct_meta_idprop_Type = {
0, /* tp_itemsize */
/* methods */
- NULL, /* tp_dealloc */
- (printfunc)NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_dealloc */
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall_offset */
+#else
+ (printfunc)NULL, /* printfunc tp_print */
+#endif
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* deprecated in Python 3.0! */
NULL, /* tp_repr */
@@ -6431,7 +6460,7 @@ PyTypeObject pyrna_struct_meta_idprop_Type = {
#if defined(_MSC_VER)
NULL, /* defer assignment */
#else
- &PyType_Type, /* struct _typeobject *tp_base; */
+ &PyType_Type, /* struct _typeobject *tp_base; */
#endif
NULL, /* PyObject *tp_dict; */
NULL, /* descrgetfunc tp_descr_get; */
@@ -6460,9 +6489,13 @@ PyTypeObject pyrna_struct_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)pyrna_struct_dealloc, /* tp_dealloc */
- (printfunc)NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall_offset */
+#else
+ (printfunc)NULL, /* printfunc tp_print */
+#endif
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in Python 3.0! */
(reprfunc)pyrna_struct_repr, /* tp_repr */
@@ -6496,7 +6529,7 @@ PyTypeObject pyrna_struct_Type = {
/* delete references to contained objects */
(inquiry)pyrna_struct_clear, /* inquiry tp_clear; */
#else
- NULL, /* traverseproc tp_traverse; */
+ NULL, /* traverseproc tp_traverse; */
/* delete references to contained objects */
NULL, /* inquiry tp_clear; */
@@ -6549,9 +6582,13 @@ PyTypeObject pyrna_prop_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)pyrna_prop_dealloc, /* tp_dealloc */
- (printfunc)NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall_offset */
+#else
+ (printfunc)NULL, /* printfunc tp_print */
+#endif
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in Python 3.0! */
(reprfunc)pyrna_prop_repr, /* tp_repr */
@@ -6633,9 +6670,13 @@ PyTypeObject pyrna_prop_array_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)pyrna_prop_array_dealloc, /* tp_dealloc */
- (printfunc)NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall_offset */
+#else
+ (printfunc)NULL, /* printfunc tp_print */
+#endif
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in Python 3.0! */
(reprfunc)pyrna_prop_array_repr, /* tp_repr */
@@ -6716,9 +6757,13 @@ PyTypeObject pyrna_prop_collection_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)pyrna_prop_dealloc, /* tp_dealloc */
- (printfunc)NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall_offset */
+#else
+ (printfunc)NULL, /* printfunc tp_print */
+#endif
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in Python 3.0! */
NULL,
@@ -6802,9 +6847,13 @@ static PyTypeObject pyrna_prop_collection_idprop_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)pyrna_prop_dealloc, /* tp_dealloc */
- (printfunc)NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall_offset */
+#else
+ (printfunc)NULL, /* printfunc tp_print */
+#endif
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in Python 3.0! */
NULL,
@@ -6887,10 +6936,14 @@ PyTypeObject pyrna_func_Type = {
sizeof(BPy_FunctionRNA), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
- NULL, /* tp_dealloc */
- (printfunc)NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_dealloc */
+#if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall_offset */
+#else
+ (printfunc)NULL, /* printfunc tp_print */
+#endif
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in Python 3.0! */
(reprfunc)pyrna_func_repr, /* tp_repr */
@@ -6984,9 +7037,13 @@ static PyTypeObject pyrna_prop_collection_iter_Type = {
0, /* tp_itemsize */
/* methods */
(destructor)pyrna_prop_collection_iter_dealloc, /* tp_dealloc */
- (printfunc)NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+# if PY_VERSION_HEX >= 0x03080000
+ 0, /* tp_vectorcall_offset */
+# else
+ (printfunc)NULL, /* printfunc tp_print */
+# endif
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
NULL,
/* tp_compare */ /* DEPRECATED in Python 3.0! */
NULL,
@@ -8093,18 +8150,11 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr,
for (link = lb->first; link; link = link->next) {
FunctionRNA *func = (FunctionRNA *)link;
const int flag = RNA_function_flag(func);
- /* TODO(campbell): this is used for classmethod's too,
- * even though class methods should have 'FUNC_USE_SELF_TYPE' set, see Operator.poll for eg.
- * Keep this as-is since it's working, but we should be using
- * 'FUNC_USE_SELF_TYPE' for many functions. */
- const bool is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
-
if (!(flag & FUNC_REGISTER)) {
continue;
}
item = PyObject_GetAttrString(py_class, RNA_function_identifier(func));
-
have_function[i] = (item != NULL);
i++;
@@ -8117,80 +8167,89 @@ static int bpy_class_validate_recursive(PointerRNA *dummyptr,
RNA_function_identifier(func));
return -1;
}
-
PyErr_Clear();
+
+ continue;
}
- else {
- /* No need to keep a ref, the class owns it
- * (technically we should keep a reference, but...). */
- Py_DECREF(item);
- if (is_staticmethod) {
- if (PyMethod_Check(item) == 0) {
- PyErr_Format(PyExc_TypeError,
- "expected %.200s, %.200s class \"%.200s\" "
- "attribute to be a static/class method, not a %.200s",
- class_type,
- py_class_name,
- RNA_function_identifier(func),
- Py_TYPE(item)->tp_name);
- return -1;
- }
- item = ((PyMethodObject *)item)->im_func;
+ /* TODO(campbell): this is used for classmethod's too,
+ * even though class methods should have 'FUNC_USE_SELF_TYPE' set, see Operator.poll for eg.
+ * Keep this as-is since it's working, but we should be using
+ * 'FUNC_USE_SELF_TYPE' for many functions. */
+ const bool is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
+
+ /* Store original so we can decrement its reference before returning. */
+ PyObject *item_orig = item;
+
+ if (is_staticmethod) {
+ if (PyMethod_Check(item) == 0) {
+ PyErr_Format(PyExc_TypeError,
+ "expected %.200s, %.200s class \"%.200s\" "
+ "attribute to be a static/class method, not a %.200s",
+ class_type,
+ py_class_name,
+ RNA_function_identifier(func),
+ Py_TYPE(item)->tp_name);
+ Py_DECREF(item_orig);
+ return -1;
}
- else {
- if (PyFunction_Check(item) == 0) {
- PyErr_Format(PyExc_TypeError,
- "expected %.200s, %.200s class \"%.200s\" "
- "attribute to be a function, not a %.200s",
- class_type,
- py_class_name,
- RNA_function_identifier(func),
- Py_TYPE(item)->tp_name);
- return -1;
- }
+ item = ((PyMethodObject *)item)->im_func;
+ }
+ else {
+ if (PyFunction_Check(item) == 0) {
+ PyErr_Format(PyExc_TypeError,
+ "expected %.200s, %.200s class \"%.200s\" "
+ "attribute to be a function, not a %.200s",
+ class_type,
+ py_class_name,
+ RNA_function_identifier(func),
+ Py_TYPE(item)->tp_name);
+ Py_DECREF(item_orig);
+ return -1;
}
+ }
- func_arg_count = rna_function_arg_count(func, &func_arg_min_count);
+ func_arg_count = rna_function_arg_count(func, &func_arg_min_count);
- if (func_arg_count >= 0) { /* -1 if we don't care. */
- arg_count = ((PyCodeObject *)PyFunction_GET_CODE(item))->co_argcount;
+ if (func_arg_count >= 0) { /* -1 if we don't care. */
+ arg_count = ((PyCodeObject *)PyFunction_GET_CODE(item))->co_argcount;
- /* note, the number of args we check for and the number of args we give to
- * '@staticmethods' are different (quirk of Python),
- * this is why rna_function_arg_count() doesn't return the value -1*/
- if (is_staticmethod) {
- func_arg_count++;
- func_arg_min_count++;
- }
+ /* note, the number of args we check for and the number of args we give to
+ * '@staticmethods' are different (quirk of Python),
+ * this is why rna_function_arg_count() doesn't return the value -1*/
+ if (is_staticmethod) {
+ func_arg_count++;
+ func_arg_min_count++;
+ }
- if (arg_count < func_arg_min_count || arg_count > func_arg_count) {
- if (func_arg_min_count != func_arg_count) {
- PyErr_Format(
- PyExc_ValueError,
- "expected %.200s, %.200s class \"%.200s\" function to have between %d and %d "
- "args, found %d",
- class_type,
- py_class_name,
- RNA_function_identifier(func),
- func_arg_count,
- func_arg_min_count,
- arg_count);
- }
- else {
- PyErr_Format(
- PyExc_ValueError,
- "expected %.200s, %.200s class \"%.200s\" function to have %d args, found %d",
- class_type,
- py_class_name,
- RNA_function_identifier(func),
- func_arg_count,
- arg_count);
- }
- return -1;
+ if (arg_count < func_arg_min_count || arg_count > func_arg_count) {
+ if (func_arg_min_count != func_arg_count) {
+ PyErr_Format(
+ PyExc_ValueError,
+ "expected %.200s, %.200s class \"%.200s\" function to have between %d and %d "
+ "args, found %d",
+ class_type,
+ py_class_name,
+ RNA_function_identifier(func),
+ func_arg_count,
+ func_arg_min_count,
+ arg_count);
+ }
+ else {
+ PyErr_Format(
+ PyExc_ValueError,
+ "expected %.200s, %.200s class \"%.200s\" function to have %d args, found %d",
+ class_type,
+ py_class_name,
+ RNA_function_identifier(func),
+ func_arg_count,
+ arg_count);
}
+ Py_DECREF(item_orig);
+ return -1;
}
}
+ Py_DECREF(item_orig);
}
/* Verify properties. */
@@ -8303,7 +8362,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
/* XXX, this is needed because render engine calls without a context
* this should be supported at some point, but at the moment it's not! */
if (C == NULL) {
- C = BPy_GetContext();
+ C = BPY_context_get();
}
/* Annoying! We need to check if the screen gets set to NULL which is a
@@ -8690,19 +8749,21 @@ void pyrna_free_types(void)
PyDoc_STRVAR(pyrna_register_class_doc,
".. method:: register_class(cls)\n"
"\n"
- " Register a subclass of a blender type in (:class:`bpy.types.Panel`,\n"
- " :class:`bpy.types.UIList`, :class:`bpy.types.Menu`, :class:`bpy.types.Header`,\n"
- " :class:`bpy.types.Operator`, :class:`bpy.types.KeyingSetInfo`,\n"
- " :class:`bpy.types.RenderEngine`).\n"
+ " Register a subclass of a Blender type class.\n"
"\n"
- " If the class has a *register* class method it will be called\n"
- " before registration.\n"
+ " :arg cls: Blender type class in:\n"
+ " :class:`bpy.types.Panel`, :class:`bpy.types.UIList`,\n"
+ " :class:`bpy.types.Menu`, :class:`bpy.types.Header`,\n"
+ " :class:`bpy.types.Operator`, :class:`bpy.types.KeyingSetInfo`,\n"
+ " :class:`bpy.types.RenderEngine`\n"
+ " :type cls: class\n"
+ " :raises ValueError:\n"
+ " if the class is not a subclass of a registerable blender class.\n"
"\n"
" .. note::\n"
"\n"
- " :exc:`ValueError` exception is raised if the class is not a\n"
- " subclass of a registerable blender class.\n"
- "\n");
+ " If the class has a *register* class method it will be called\n"
+ " before registration.\n");
PyMethodDef meth_bpy_register_class = {
"register_class", pyrna_register_class, METH_O, pyrna_register_class_doc};
static PyObject *pyrna_register_class(PyObject *UNUSED(self), PyObject *py_class)
@@ -8770,7 +8831,7 @@ static PyObject *pyrna_register_class(PyObject *UNUSED(self), PyObject *py_class
}
/* Get the context, so register callback can do necessary refreshes. */
- C = BPy_GetContext();
+ C = BPY_context_get();
/* Call the register callback with reports & identifier. */
BKE_reports_init(&reports, RPT_STORE);
@@ -8808,7 +8869,10 @@ static PyObject *pyrna_register_class(PyObject *UNUSED(self), PyObject *py_class
/* Old srna still references us, keep the check in case registering somehow can free it. */
if (RNA_struct_py_type_get(srna)) {
RNA_struct_py_type_set(srna, NULL);
- // Py_DECREF(py_class); /* Should be able to do this XXX since the old RNA adds a new ref. */
+#if 0
+ /* Should be able to do this XXX since the old RNA adds a new ref. */
+ Py_DECREF(py_class);
+#endif
}
/* Can't use this because it returns a dict proxy
@@ -8978,7 +9042,7 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla
}
/* Get the context, so register callback can do necessary refreshes. */
- C = BPy_GetContext();
+ C = BPY_context_get();
/* Call unregister. */
unreg(CTX_data_main(C), srna); /* Calls bpy_class_free, this decref's py_class. */
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 1d52706c5f9..b7648ee830f 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -259,7 +259,7 @@ static int pyrna_struct_keyframe_parse(PointerRNA *ptr,
}
if (*r_cfra == FLT_MAX) {
- *r_cfra = CTX_data_scene(BPy_GetContext())->r.cfra;
+ *r_cfra = CTX_data_scene(BPY_context_get())->r.cfra;
}
/* flag may be null (no option currently for remove keyframes e.g.). */
@@ -341,7 +341,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
* It is unlikely that driver code (which is the reason this depsgraph pointer is obtained) will
* be executed from this function call, as this only happens when `options` has
* `INSERTKEY_DRIVER`, which is not exposed to Python. */
- bContext *C = BPy_GetContext();
+ bContext *C = BPY_context_get();
struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
cfra);
@@ -498,7 +498,7 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb
int i;
/* try to find index of beztriple to get rid of */
- i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found);
+ i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
if (found) {
/* delete the key at the index (will sanity check + do recalc afterwards) */
delete_fcurve_key(fcu, i, 1);
@@ -600,8 +600,8 @@ PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args)
ret = pyrna_struct_CreatePyObject(&tptr);
}
- bContext *context = BPy_GetContext();
- WM_event_add_notifier(BPy_GetContext(), NC_ANIMATION | ND_FCURVES_ORDER, NULL);
+ bContext *context = BPY_context_get();
+ WM_event_add_notifier(BPY_context_get(), NC_ANIMATION | ND_FCURVES_ORDER, NULL);
DEG_relations_tag_update(CTX_data_main(context));
}
else {
@@ -659,7 +659,7 @@ PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args)
return NULL;
}
- bContext *context = BPy_GetContext();
+ bContext *context = BPY_context_get();
WM_event_add_notifier(context, NC_ANIMATION | ND_FCURVES_ORDER, NULL);
DEG_relations_tag_update(CTX_data_main(context));
diff --git a/source/blender/python/intern/bpy_rna_gizmo.c b/source/blender/python/intern/bpy_rna_gizmo.c
index 542d014f8b2..1f27e4bcca8 100644
--- a/source/blender/python/intern/bpy_rna_gizmo.c
+++ b/source/blender/python/intern/bpy_rna_gizmo.c
@@ -433,14 +433,14 @@ static PyObject *bpy_gizmo_target_set_value(PyObject *UNUSED(self), PyObject *ar
"Gizmo target property array") == -1) {
goto fail;
}
- WM_gizmo_target_property_float_set_array(BPy_GetContext(), gz, gz_prop, value);
+ WM_gizmo_target_property_float_set_array(BPY_context_get(), gz, gz_prop, value);
}
else {
float value;
if ((value = PyFloat_AsDouble(params.value)) == -1.0f && PyErr_Occurred()) {
goto fail;
}
- WM_gizmo_target_property_float_set(BPy_GetContext(), gz, gz_prop, value);
+ WM_gizmo_target_property_float_set(BPY_context_get(), gz, gz_prop, value);
}
Py_RETURN_NONE;
}
diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c
index 30623724593..042f7b6fd67 100644
--- a/source/blender/python/intern/bpy_rna_types_capi.c
+++ b/source/blender/python/intern/bpy_rna_types_capi.c
@@ -87,7 +87,7 @@ static struct PyMethodDef pyrna_uilayout_methods[] = {
/* -------------------------------------------------------------------- */
/** \name Window Manager Clipboard Property
*
- * Avoid using the RNA API because this value may change between checking it's length
+ * Avoid using the RNA API because this value may change between checking its length
* and creating the buffer, causing writes past the allocated length.
* \{ */
diff --git a/source/blender/python/intern/bpy_rna_ui.c b/source/blender/python/intern/bpy_rna_ui.c
index 9f37b8300db..ec92eadfd72 100644
--- a/source/blender/python/intern/bpy_rna_ui.c
+++ b/source/blender/python/intern/bpy_rna_ui.c
@@ -17,7 +17,7 @@
/** \file
* \ingroup pythonintern
*
- * This adds helpers to #uiLayout which can't be added easily to RNA it's self.
+ * This adds helpers to #uiLayout which can't be added easily to RNA itself.
*/
#include <Python.h>
@@ -29,6 +29,7 @@
#include "UI_interface.h"
#include "bpy_rna.h"
+#include "bpy_rna_ui.h"
PyDoc_STRVAR(bpy_rna_uilayout_introspect_doc,
".. method:: introspect()\n"
diff --git a/source/blender/python/intern/bpy_utils_previews.c b/source/blender/python/intern/bpy_utils_previews.c
index 81b44dd5c43..7a826d99a3d 100644
--- a/source/blender/python/intern/bpy_utils_previews.c
+++ b/source/blender/python/intern/bpy_utils_previews.c
@@ -49,15 +49,20 @@
#define STR_SOURCE_TYPES "'IMAGE', 'MOVIE', 'BLEND', 'FONT'"
-PyDoc_STRVAR(bpy_utils_previews_new_doc,
- ".. method:: new(name)\n"
- "\n"
- " Generate a new empty preview, or return existing one matching ``name``.\n"
- "\n"
- " :arg name: The name (unique id) identifying the preview.\n"
- " :type name: string\n"
- " :return: The Preview matching given name, or a new empty one.\n"
- " :rtype: :class:`bpy.types.ImagePreview`\n");
+PyDoc_STRVAR(
+ bpy_utils_previews_new_doc,
+ ".. method:: new(name)\n"
+ "\n"
+ " Generate a new empty preview.\n"
+ "\n"
+ " :arg name: The name (unique id) identifying the preview.\n"
+ " :type name: string\n"
+ " :return: The Preview matching given name, or a new empty one.\n"
+ " :rtype: :class:`bpy.types.ImagePreview`\n"
+ " :rtype: :class:`bpy.types.ImagePreview`\n"
+ /* This is only true when accessed via 'bpy.utils.previews.ImagePreviewCollection.load',
+ * however this is the public API, allow this minor difference to the internal version here. */
+ " :raises KeyError: if ``name`` already exists.");
static PyObject *bpy_utils_previews_new(PyObject *UNUSED(self), PyObject *args)
{
char *name;
@@ -78,7 +83,7 @@ PyDoc_STRVAR(
bpy_utils_previews_load_doc,
".. method:: load(name, filepath, filetype, force_reload=False)\n"
"\n"
- " Generate a new preview from given file path, or return existing one matching ``name``.\n"
+ " Generate a new preview from given file path.\n"
"\n"
" :arg name: The name (unique id) identifying the preview.\n"
" :type name: string\n"
@@ -91,7 +96,10 @@ PyDoc_STRVAR(
"exists in cache.\n"
" :type force_reload: bool\n"
" :return: The Preview matching given name, or a new empty one.\n"
- " :rtype: :class:`bpy.types.ImagePreview`\n");
+ " :rtype: :class:`bpy.types.ImagePreview`\n"
+ /* This is only true when accessed via 'bpy.utils.previews.ImagePreviewCollection.load',
+ * however this is the public API, allow this minor difference to the internal version here. */
+ " :raises KeyError: if ``name`` already exists.");
static PyObject *bpy_utils_previews_load(PyObject *UNUSED(self), PyObject *args)
{
char *name, *path, *path_type_s;
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index a58e2bcb975..b460ef5e0c0 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -73,15 +73,15 @@ static PyStructSequence_Field bpyunits_systems_fields[ARRAY_SIZE(bpyunits_usyste
static PyStructSequence_Field bpyunits_categories_fields[ARRAY_SIZE(bpyunits_ucategorie_items)];
static PyStructSequence_Desc bpyunits_systems_desc = {
- "bpy.utils.units.systems", /* name */
- "This named tuple contains all pre-defined unit systems", /* doc */
- bpyunits_systems_fields, /* fields */
+ "bpy.utils.units.systems", /* name */
+ "This named tuple contains all predefined unit systems", /* doc */
+ bpyunits_systems_fields, /* fields */
ARRAY_SIZE(bpyunits_systems_fields) - 1,
};
static PyStructSequence_Desc bpyunits_categories_desc = {
- "bpy.utils.units.categories", /* name */
- "This named tuple contains all pre-defined unit names", /* doc */
- bpyunits_categories_fields, /* fields */
+ "bpy.utils.units.categories", /* name */
+ "This named tuple contains all predefined unit names", /* doc */
+ bpyunits_categories_fields, /* fields */
ARRAY_SIZE(bpyunits_categories_fields) - 1,
};