diff options
Diffstat (limited to 'source/blender/python/intern')
20 files changed, 224 insertions, 241 deletions
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 3377b2c283e..c792773272b 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -94,10 +94,13 @@ static PyObject *bpy_script_paths(PyObject *UNUSED(self)) return ret; } -static bool bpy_blend_paths_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src) +static bool bpy_blend_foreach_path_cb(BPathForeachPathData *bpath_data, + char *UNUSED(path_dst), + const char *path_src) { - PyList_APPEND((PyObject *)userdata, PyC_UnicodeFromByte(path_src)); - return false; /* never edits the path */ + PyObject *py_list = bpath_data->user_data; + PyList_APPEND(py_list, PyC_UnicodeFromByte(path_src)); + return false; /* Never edits the path. */ } PyDoc_STRVAR(bpy_blend_paths_doc, @@ -115,7 +118,7 @@ PyDoc_STRVAR(bpy_blend_paths_doc, " :rtype: list of strings\n"); static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - int flag = 0; + eBPathForeachFlag flag = 0; PyObject *list; bool absolute = false; @@ -137,18 +140,23 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec } if (absolute) { - flag |= BKE_BPATH_TRAVERSE_ABS; + flag |= BKE_BPATH_FOREACH_PATH_ABSOLUTE; } if (!packed) { - flag |= BKE_BPATH_TRAVERSE_SKIP_PACKED; + flag |= BKE_BPATH_FOREACH_PATH_SKIP_PACKED; } if (local) { - flag |= BKE_BPATH_TRAVERSE_SKIP_LIBRARY; + flag |= BKE_BPATH_FOREACH_PATH_SKIP_LINKED; } list = PyList_New(0); - BKE_bpath_traverse_main(G_MAIN, bpy_blend_paths_visit_cb, flag, (void *)list); + BKE_bpath_foreach_path_main(&(BPathForeachPathData){ + .bmain = G_MAIN, + .callback_function = bpy_blend_foreach_path_cb, + .flag = flag, + .user_data = list, + }); return list; } @@ -442,9 +450,6 @@ static PyObject *bpy_import_test(const char *modname) return mod; } -/****************************************************************************** - * Description: Creates the bpy module and adds it to sys.modules for importing - ******************************************************************************/ void BPy_init_modules(struct bContext *C) { PointerRNA ctx_ptr; diff --git a/source/blender/python/intern/bpy.h b/source/blender/python/intern/bpy.h index 25a047edfb5..b77a3e9fb7d 100644 --- a/source/blender/python/intern/bpy.h +++ b/source/blender/python/intern/bpy.h @@ -26,7 +26,9 @@ extern "C" { struct bContext; +/** Creates the bpy module and adds it to `sys.modules` for importing. */ void BPy_init_modules(struct bContext *C); + extern PyObject *bpy_package_py; /* bpy_interface_atexit.c */ diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c index de70035eb2b..4fa71c0c976 100644 --- a/source/blender/python/intern/bpy_app_translations.c +++ b/source/blender/python/intern/bpy_app_translations.c @@ -69,12 +69,12 @@ static BlenderAppTranslations *_translations = NULL; /** \} */ -#ifdef WITH_INTERNATIONAL - /* ------------------------------------------------------------------- */ /** \name Helpers for GHash * \{ */ +#ifdef WITH_INTERNATIONAL + typedef struct GHashKey { const char *msgctxt; const char *msgid; diff --git a/source/blender/python/intern/bpy_capi_utils.c b/source/blender/python/intern/bpy_capi_utils.c index 8e9d8c02c03..ed01132ed4e 100644 --- a/source/blender/python/intern/bpy_capi_utils.c +++ b/source/blender/python/intern/bpy_capi_utils.c @@ -56,9 +56,6 @@ short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool return (report_str == NULL) ? 0 : -1; } -/** - * A version of #BKE_report_write_file_fp that uses Python's stdout. - */ void BPy_reports_write_stdout(const ReportList *reports, const char *header) { if (header) { diff --git a/source/blender/python/intern/bpy_capi_utils.h b/source/blender/python/intern/bpy_capi_utils.h index 80e92d918ac..0e4a28fb657 100644 --- a/source/blender/python/intern/bpy_capi_utils.h +++ b/source/blender/python/intern/bpy_capi_utils.h @@ -33,6 +33,9 @@ struct ReportList; /* error reporting */ short BPy_reports_to_error(struct ReportList *reports, PyObject *exception, const bool clear); +/** + * A version of #BKE_report_write_file_fp that uses Python's stdout. + */ void BPy_reports_write_stdout(const struct ReportList *reports, const char *header); bool BPy_errors_to_report_ex(struct ReportList *reports, const char *error_prefix, @@ -44,6 +47,9 @@ bool BPy_errors_to_report(struct ReportList *reports); struct bContext *BPY_context_get(void); extern void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate); +/** + * Context should be used but not now because it causes some bugs. + */ extern void bpy_context_clear(struct bContext *C, const PyGILState_STATE *gilstate); #ifdef __cplusplus diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c index 7effa25e6e8..bd1f3cd301f 100644 --- a/source/blender/python/intern/bpy_driver.c +++ b/source/blender/python/intern/bpy_driver.c @@ -57,19 +57,12 @@ # include <opcode.h> #endif -/** - * For PyDrivers - * (drivers using one-line Python expressions to express relationships between targets). - */ PyObject *bpy_pydriver_Dict = NULL; #ifdef USE_BYTECODE_WHITELIST static PyObject *bpy_pydriver_Dict__whitelist = NULL; #endif -/* For faster execution we keep a special dictionary for pydrivers, with - * the needed modules and aliases. - */ int bpy_pydriver_create_dict(void) { PyObject *d, *mod; @@ -220,11 +213,6 @@ static void bpy_pydriver_namespace_clear_self(void) } } -/* Update function, it gets rid of pydrivers global dictionary, forcing - * BPY_driver_exec to recreate it. This function is used to force - * reloading the Blender text module "pydrivers.py", if available, so - * updates in it reach pydriver evaluation. - */ void BPY_driver_reset(void) { PyGILState_STATE gilstate; @@ -429,28 +417,24 @@ static void bpy_pydriver_namespace_add_depsgraph(PyObject *driver_vars, } } -/** - * This evaluates Python driver expressions, `driver_orig->expression` - * is a Python expression that should evaluate to a float number, which is returned. - * - * (old) NOTE: PyGILState_Ensure() isn't always called because python can call - * the bake operator which intern starts a thread which calls scene update - * which does a driver update. to avoid a deadlock check #PyC_IsInterpreterActive() - * if #PyGILState_Ensure() is needed, see T27683. - * - * (new) NOTE: checking if python is running is not thread-safe T28114 - * now release the GIL on python operator execution instead, using - * #PyEval_SaveThread() / #PyEval_RestoreThread() so we don't lock up blender. - * - * For copy-on-write we always cache expressions and write errors in the - * original driver, otherwise these would get freed while editing. Due to - * the GIL this is thread-safe. - */ float BPY_driver_exec(struct PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, const AnimationEvalContext *anim_eval_context) { + /* (old) NOTE: PyGILState_Ensure() isn't always called because python can call + * the bake operator which intern starts a thread which calls scene update + * which does a driver update. to avoid a deadlock check #PyC_IsInterpreterActive() + * if #PyGILState_Ensure() is needed, see T27683. + * + * (new) NOTE: checking if python is running is not thread-safe T28114 + * now release the GIL on python operator execution instead, using + * #PyEval_SaveThread() / #PyEval_RestoreThread() so we don't lock up blender. + * + * For copy-on-write we always cache expressions and write errors in the + * original driver, otherwise these would get freed while editing. + * Due to the GIL this is thread-safe. */ + PyObject *driver_vars = NULL; PyObject *retval = NULL; diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h index d5064d9fa56..b7bb0f846e8 100644 --- a/source/blender/python/intern/bpy_driver.h +++ b/source/blender/python/intern/bpy_driver.h @@ -24,7 +24,15 @@ extern "C" { #endif +/** + * For faster execution we keep a special dictionary for py-drivers, with + * the needed modules and aliases. + */ int bpy_pydriver_create_dict(void); +/** + * For PyDrivers + * (drivers using one-line Python expressions to express relationships between targets). + */ extern PyObject *bpy_pydriver_Dict; #ifdef __cplusplus diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 95affa9dba9..faa668df775 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -80,6 +80,7 @@ #include "../mathutils/mathutils.h" /* 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"); @@ -103,7 +104,6 @@ static double bpy_timer_run; /* time for each python script run */ static double bpy_timer_run_tot; /* accumulate python runs */ #endif -/* use for updating while a python script runs - in case of file load */ void BPY_context_update(bContext *C) { /* don't do this from a non-main (e.g. render) thread, it can cause a race @@ -141,7 +141,6 @@ void bpy_context_set(bContext *C, PyGILState_STATE *gilstate) } } -/* context should be used but not now because it causes some bugs */ void bpy_context_clear(bContext *UNUSED(C), const PyGILState_STATE *gilstate) { py_call_level--; @@ -175,16 +174,6 @@ static void bpy_context_end(bContext *C) CTX_wm_operator_poll_msg_clear(C); } -/** - * 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[], @@ -238,9 +227,6 @@ void BPY_text_free_code(Text *text) } } -/** - * 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. */ @@ -333,7 +319,6 @@ static void pystatus_exit_on_error(PyStatus status) } #endif -/* call BPY_context_set first */ void BPY_python_start(bContext *C, int argc, const char **argv) { #ifndef WITH_PYTHON_MODULE @@ -881,9 +866,6 @@ static void bpy_module_free(void *UNUSED(mod)) #endif -/** - * Avoids duplicating keyword list. - */ bool BPY_string_is_keyword(const char *str) { /* list is from... @@ -905,8 +887,7 @@ bool BPY_string_is_keyword(const char *str) return false; } -/* EVIL, define text.c functions here... */ -/* BKE_text.h */ +/* EVIL: define `text.c` functions here (declared in `BKE_text.h`). */ int text_check_identifier_unicode(const uint ch) { return (ch < 255 && text_check_identifier((char)ch)) || Py_UNICODE_ISALNUM(ch); diff --git a/source/blender/python/intern/bpy_interface_run.c b/source/blender/python/intern/bpy_interface_run.c index f7d6a33c904..bc21c91074f 100644 --- a/source/blender/python/intern/bpy_interface_run.c +++ b/source/blender/python/intern/bpy_interface_run.c @@ -80,6 +80,14 @@ typedef struct { } PyModuleObject; #endif +/** + * Execute a file-path or text-block. + * + * \param reports: Report exceptions as errors (may be NULL). + * \param do_jump: See #BPY_run_text. + * + * \note Share a function for this since setup/cleanup logic is the same. + */ static bool python_script_exec( bContext *C, const char *fn, struct Text *text, struct ReportList *reports, const bool do_jump) { @@ -212,7 +220,6 @@ static bool python_script_exec( /** \name Run Text / Filename / String * \{ */ -/* Can run a file or text block */ bool BPY_run_filepath(bContext *C, const char *filepath, struct ReportList *reports) { return python_script_exec(C, filepath, NULL, reports, false); @@ -271,17 +278,11 @@ static bool bpy_run_string_impl(bContext *C, return ok; } -/** - * Run an expression, matches: `exec(compile(..., "eval"))` - */ bool BPY_run_string_eval(bContext *C, const char *imports[], const char *expr) { return bpy_run_string_impl(C, imports, expr, Py_eval_input); } -/** - * Run an entire script, matches: `exec(compile(..., "exec"))` - */ bool BPY_run_string_exec(bContext *C, const char *imports[], const char *expr) { return bpy_run_string_impl(C, imports, expr, Py_file_input); @@ -330,9 +331,6 @@ static void run_string_handle_error(struct BPy_RunErrInfo *err_info) Py_XDECREF(py_err_str); } -/** - * \return success - */ bool BPY_run_string_as_number(bContext *C, const char *imports[], const char *expr, @@ -342,10 +340,6 @@ bool BPY_run_string_as_number(bContext *C, PyGILState_STATE gilstate; bool ok = true; - if (!r_value || !expr) { - return -1; - } - if (expr[0] == '\0') { *r_value = 0.0; return ok; @@ -364,9 +358,6 @@ bool BPY_run_string_as_number(bContext *C, return ok; } -/** - * \return success - */ bool BPY_run_string_as_string_and_size(bContext *C, const char *imports[], const char *expr, @@ -374,7 +365,6 @@ bool BPY_run_string_as_string_and_size(bContext *C, char **r_value, size_t *r_value_size) { - BLI_assert(r_value && expr); PyGILState_STATE gilstate; bool ok = true; @@ -406,18 +396,12 @@ bool BPY_run_string_as_string(bContext *C, return BPY_run_string_as_string_and_size(C, imports, expr, err_info, r_value, &value_dummy_size); } -/** - * Support both int and pointers. - * - * \return success - */ bool BPY_run_string_as_intptr(bContext *C, const char *imports[], const char *expr, struct BPy_RunErrInfo *err_info, intptr_t *r_value) { - BLI_assert(r_value && expr); PyGILState_STATE gilstate; bool ok = true; diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 059d692a9ba..fe279c0b940 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -34,6 +34,7 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BKE_blendfile_link_append.h" #include "BKE_context.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" @@ -346,11 +347,63 @@ static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item) PyErr_Restore(exc, val, tb); } +struct LibExitLappContextItemsIterData { + short idcode; + BPy_Library *py_library; + PyObject *py_list; + Py_ssize_t py_list_size; +}; + +static bool bpy_lib_exit_lapp_context_items_cb(BlendfileLinkAppendContext *lapp_context, + BlendfileLinkAppendContextItem *item, + void *userdata) +{ + struct LibExitLappContextItemsIterData *data = userdata; + + /* Since `bpy_lib_exit` loops over all ID types, all items in `lapp_context` end up being looped + * over for each ID type, so when it does not match the item can simply be skipped: it either has + * already been processed, or will be processed in a later loop. */ + if (BKE_blendfile_link_append_context_item_idcode_get(lapp_context, item) != data->idcode) { + return true; + } + + const int py_list_index = POINTER_AS_INT( + BKE_blendfile_link_append_context_item_userdata_get(lapp_context, item)); + ID *new_id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item); + + BLI_assert(py_list_index < data->py_list_size); + + /* Fully invalid items (which got set to `Py_None` already in first loop of `bpy_lib_exit`) + * should never be accessed here, since their index should never be set to any item in + * `lapp_context`. */ + PyObject *item_src = PyList_GET_ITEM(data->py_list, py_list_index); + BLI_assert(item_src != Py_None); + + PyObject *py_item; + if (new_id != NULL) { + PointerRNA newid_ptr; + RNA_id_pointer_create(new_id, &newid_ptr); + py_item = pyrna_struct_CreatePyObject(&newid_ptr); + } + else { + const char *item_idname = PyUnicode_AsUTF8(item_src); + const char *idcode_name_plural = BKE_idtype_idcode_to_name_plural(data->idcode); + + bpy_lib_exit_warn_idname(data->py_library, idcode_name_plural, item_idname); + + py_item = Py_INCREF_RET(Py_None); + } + + PyList_SET_ITEM(data->py_list, py_list_index, py_item); + + Py_DECREF(item_src); + + return true; +} + static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) { Main *bmain = self->bmain; - Main *mainl = NULL; - const int err = 0; const bool do_append = ((self->flag & FILE_LINK) == 0); BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); @@ -360,134 +413,100 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) struct LibraryLink_Params liblink_params; BLO_library_link_params_init(&liblink_params, bmain, self->flag, id_tag_extra); - mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params); - - { - int idcode_step = 0, idcode; - while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) { - if (BKE_idtype_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) { - const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode); - PyObject *ls = PyDict_GetItemString(self->dict, name_plural); - // printf("lib: %s\n", name_plural); - if (ls && PyList_Check(ls)) { - /* loop */ - const Py_ssize_t size = PyList_GET_SIZE(ls); - Py_ssize_t i; - - for (i = 0; i < size; i++) { - PyObject *item_src = PyList_GET_ITEM(ls, i); - PyObject *item_dst; /* must be set below */ - const char *item_idname = PyUnicode_AsUTF8(item_src); - - // printf(" %s\n", item_idname); - - if (item_idname) { - ID *id = BLO_library_link_named_part( - mainl, &(self->blo_handle), idcode, item_idname, &liblink_params); - if (id) { - - if (self->bmain_is_temp) { - /* If this fails, #LibraryLink_Params.id_tag_extra is not being applied. */ - BLI_assert(id->tag & LIB_TAG_TEMP_MAIN); - } + BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new( + &liblink_params); + BKE_blendfile_link_append_context_library_add(lapp_context, self->abspath, self->blo_handle); -#ifdef USE_RNA_DATABLOCKS - /* swap name for pointer to the id */ - item_dst = PyCapsule_New((void *)id, NULL, NULL); -#else - /* leave as is */ - continue; -#endif - } - else { - bpy_lib_exit_warn_idname(self, name_plural, item_idname); - /* just warn for now */ - /* err = -1; */ - item_dst = Py_INCREF_RET(Py_None); - } - - /* ID or None */ - } - else { - /* XXX, could complain about this */ - bpy_lib_exit_warn_type(self, item_src); - PyErr_Clear(); - item_dst = Py_INCREF_RET(Py_None); - } - - /* item_dst must be new or already incref'd */ - Py_DECREF(item_src); - PyList_SET_ITEM(ls, i, item_dst); - } - } - } + int idcode_step = 0; + short idcode; + while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) { + if (!BKE_idtype_idcode_is_linkable(idcode) || (idcode == ID_WS && !do_append)) { + continue; } - } - if (err == -1) { - /* exception raised above, XXX, this leaks some memory */ - BLO_blendhandle_close(self->blo_handle); - self->blo_handle = NULL; - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - return NULL; - } + const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode); + PyObject *ls = PyDict_GetItemString(self->dict, name_plural); + // printf("lib: %s\n", name_plural); + if (ls == NULL || !PyList_Check(ls)) { + continue; + } - Library *lib = mainl->curlib; /* newly added lib, assign before append end */ - BLO_library_link_end(mainl, &(self->blo_handle), &liblink_params); - BLO_blendhandle_close(self->blo_handle); - self->blo_handle = NULL; + const Py_ssize_t size = PyList_GET_SIZE(ls); + if (size == 0) { + continue; + } - GHash *old_to_new_ids = BLI_ghash_ptr_new(__func__); + /* loop */ + for (Py_ssize_t i = 0; i < size; i++) { + PyObject *item_src = PyList_GET_ITEM(ls, i); + const char *item_idname = PyUnicode_AsUTF8(item_src); - /* copied from wm_operator.c */ - { - /* mark all library linked objects to be updated */ - BKE_main_lib_objects_recalc_all(bmain); + // printf(" %s\n", item_idname); - /* append, rather than linking */ - if (do_append) { - BKE_library_make_local(bmain, lib, old_to_new_ids, true, false); + /* NOTE: index of item in py list is stored in userdata pointer, so that it can be found + * later on to replace the ID name by the actual ID pointer. */ + if (item_idname != NULL) { + BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add( + lapp_context, item_idname, idcode, POINTER_FROM_INT(i)); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0); + } + else { + /* XXX, could complain about this */ + bpy_lib_exit_warn_type(self, item_src); + PyErr_Clear(); + +#ifdef USE_RNA_DATABLOCKS + /* We can replace the item immediately with `None`. */ + PyObject *py_item = Py_INCREF_RET(Py_None); + PyList_SET_ITEM(ls, i, py_item); + Py_DECREF(item_src); +#endif + } } } - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + BKE_blendfile_link(lapp_context, NULL); + if (do_append) { + BKE_blendfile_append(lapp_context, NULL); + } - /* finally swap the capsules for real bpy objects - * important since BLO_library_append_end initializes NodeTree types used by srna->refine */ + /* If enabled, replace named items in given lists by the final matching new ID pointer. */ #ifdef USE_RNA_DATABLOCKS - { - int idcode_step = 0, idcode; - while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) { - if (BKE_idtype_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) { - const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode); - PyObject *ls = PyDict_GetItemString(self->dict, name_plural); - if (ls && PyList_Check(ls)) { - const Py_ssize_t size = PyList_GET_SIZE(ls); - Py_ssize_t i; - PyObject *item; - - for (i = 0; i < size; i++) { - item = PyList_GET_ITEM(ls, i); - if (PyCapsule_CheckExact(item)) { - PointerRNA id_ptr; - ID *id; - - id = PyCapsule_GetPointer(item, NULL); - id = BLI_ghash_lookup_default(old_to_new_ids, id, id); - Py_DECREF(item); - - RNA_id_pointer_create(id, &id_ptr); - item = pyrna_struct_CreatePyObject(&id_ptr); - PyList_SET_ITEM(ls, i, item); - } - } - } - } + idcode_step = 0; + while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) { + if (!BKE_idtype_idcode_is_linkable(idcode) || (idcode == ID_WS && !do_append)) { + continue; + } + const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode); + PyObject *ls = PyDict_GetItemString(self->dict, name_plural); + // printf("lib: %s\n", name_plural); + if (ls == NULL || !PyList_Check(ls)) { + continue; } + + const Py_ssize_t size = PyList_GET_SIZE(ls); + if (size == 0) { + continue; + } + + /* Loop over linked items in `lapp_context` to find matching python one in the list, and + * replace them with proper ID pointer. */ + struct LibExitLappContextItemsIterData iter_data = { + .idcode = idcode, .py_library = self, .py_list = ls, .py_list_size = size}; + BKE_blendfile_link_append_context_item_foreach( + lapp_context, + bpy_lib_exit_lapp_context_items_cb, + BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT, + &iter_data); } -#endif /* USE_RNA_DATABLOCKS */ +#endif // USE_RNA_DATABLOCKS + + BLO_blendhandle_close(self->blo_handle); + self->blo_handle = NULL; + + BKE_blendfile_link_append_context_free(lapp_context); + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - BLI_ghash_free(old_to_new_ids, NULL, NULL); Py_RETURN_NONE; } diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index c2d7257e458..bee64f5de2c 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -115,10 +115,6 @@ static void operator_properties_init(wmOperatorType *ot) /* end 'ot->prop' assignment */ } -/** - * Generic function used by all Python defined operators - * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration. - */ void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata) { /* take care not to overwrite anything set in @@ -135,10 +131,6 @@ void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata) operator_properties_init(ot); } -/** - * Generic function used by all Python defined macro-operators - * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration. - */ void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata) { wmOperatorType *data = (wmOperatorType *)userdata; diff --git a/source/blender/python/intern/bpy_operator_wrap.h b/source/blender/python/intern/bpy_operator_wrap.h index 9e496cd8d26..41deb06814b 100644 --- a/source/blender/python/intern/bpy_operator_wrap.h +++ b/source/blender/python/intern/bpy_operator_wrap.h @@ -30,7 +30,15 @@ extern "C" { PyObject *PYOP_wrap_macro_define(PyObject *self, PyObject *args); /* exposed to rna/wm api */ +/** + * Generic function used by all Python defined operators + * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration. + */ void BPY_RNA_operator_wrapper(struct wmOperatorType *ot, void *userdata); +/** + * Generic function used by all Python defined macro-operators + * it's passed as an argument to #WM_operatortype_append_ptr in for operator registration. + */ void BPY_RNA_operator_macro_wrapper(struct wmOperatorType *ot, void *userdata); #ifdef __cplusplus diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 13c7d2947cf..ed9547ee13f 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -434,6 +434,10 @@ static PyObject *bpy_prop_deferred_data_CreatePyObject(PyObject *fn, PyObject *k /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Shared Property Utilities + * \{ */ + /* PyObject's */ static PyObject *pymeth_BoolProperty = NULL; static PyObject *pymeth_BoolVectorProperty = NULL; @@ -2630,10 +2634,14 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p) " This function must take 2 values (self, value) and return None.\n" \ " :type set: function\n" -#define BPY_PROPDEF_TYPE_DOC \ +#define BPY_PROPDEF_POINTER_TYPE_DOC \ " :arg type: A subclass of :class:`bpy.types.PropertyGroup` or :class:`bpy.types.ID`.\n" \ " :type type: class\n" +#define BPY_PROPDEF_COLLECTION_TYPE_DOC \ + " :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n" \ + " :type type: class\n" + #define BPY_PROPDEF_TAGS_DOC \ " :arg tags: Enumerator of tags that are defined by parent class.\n" \ " :type tags: set\n" @@ -3981,7 +3989,7 @@ PyDoc_STRVAR(BPy_PointerProperty_doc, "update=None)\n" "\n" " Returns a new pointer property definition.\n" - "\n" BPY_PROPDEF_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC + "\n" BPY_PROPDEF_POINTER_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_POLL_DOC BPY_PROPDEF_UPDATE_DOC); PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) @@ -4104,7 +4112,7 @@ PyDoc_STRVAR(BPy_CollectionProperty_doc, "tags=set())\n" "\n" " Returns a new collection property definition.\n" - "\n" BPY_PROPDEF_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC + "\n" BPY_PROPDEF_COLLECTION_TYPE_DOC BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_COLLECTION_DOC BPY_PROPDEF_TAGS_DOC); PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) @@ -4392,10 +4400,6 @@ PyObject *BPY_rna_props(void) return submodule; } -/** - * Run this on exit, clearing all Python callback users and disable the RNA callback, - * as it would be called after Python has already finished. - */ void BPY_rna_props_clear_all(void) { /* Remove all user counts, so this isn't considered a leak from Python's perspective. */ diff --git a/source/blender/python/intern/bpy_props.h b/source/blender/python/intern/bpy_props.h index e6bbd6f708d..9d739540919 100644 --- a/source/blender/python/intern/bpy_props.h +++ b/source/blender/python/intern/bpy_props.h @@ -25,6 +25,10 @@ extern "C" { #endif PyObject *BPY_rna_props(void); +/** + * Run this on exit, clearing all Python callback users and disable the RNA callback, + * as it would be called after Python has already finished. + */ void BPY_rna_props_clear_all(void); PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 707de1c2581..a79a0ed32bf 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1462,10 +1462,6 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) return ret; } -/** - * This function is used by operators and converting dicts into collections. - * It takes keyword args and fills them with property values. - */ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const bool all_args, @@ -7545,7 +7541,6 @@ PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop) return (PyObject *)pyrna; } -/* Utility func to be used by external modules, sneaky! */ PyObject *pyrna_id_CreatePyObject(ID *id) { if (id) { @@ -7777,9 +7772,6 @@ static struct PyModuleDef bpy_types_module_def = { NULL, /* m_free */ }; -/** - * Accessed from Python as 'bpy.types' - */ PyObject *BPY_rna_types(void) { PyObject *submodule = PyModule_Create(&bpy_types_module_def); @@ -7864,11 +7856,6 @@ StructRNA *pyrna_struct_as_srna(PyObject *self, const bool parent, const char *e } /* Orphan functions, not sure where they should go. */ -/** - * Get the SRNA for methods attached to types. - * - * Caller needs to raise error. - */ StructRNA *srna_from_self(PyObject *self, const char *error_prefix) { @@ -9094,9 +9081,6 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla Py_RETURN_NONE; } -/** - * Extend RNA types with C/API methods, properties. - */ void pyrna_struct_type_extend_capi(struct StructRNA *srna, struct PyMethodDef *method, struct PyGetSetDef *getset) diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 2096734ef96..9a6339c0a89 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -401,6 +401,10 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb return NULL; } + if (result) { + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + } + return PyBool_FromLong(result); } diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c index fcc796d4545..270c9ad431c 100644 --- a/source/blender/python/intern/bpy_rna_array.c +++ b/source/blender/python/intern/bpy_rna_array.c @@ -990,9 +990,10 @@ PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop) return pyrna_prop_CreatePyObject(ptr, prop); } -/* TODO: multi-dimensional arrays. */ int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value) { + /* TODO: multi-dimensional arrays. */ + const int len = RNA_property_array_length(ptr, prop); int type; int i; diff --git a/source/blender/python/intern/bpy_rna_data.c b/source/blender/python/intern/bpy_rna_data.c index 639999b69d4..c781fe4a4e7 100644 --- a/source/blender/python/intern/bpy_rna_data.c +++ b/source/blender/python/intern/bpy_rna_data.c @@ -177,7 +177,7 @@ static PyObject *bpy_rna_data_temp_data(PyObject *UNUSED(self), PyObject *args, ret = PyObject_GC_New(BPy_DataContext, &bpy_rna_data_context_Type); - STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->name); + STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->filepath); return (PyObject *)ret; } diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c index 3bddd0ad8c0..0bb8b1ba3e1 100644 --- a/source/blender/python/intern/bpy_rna_driver.c +++ b/source/blender/python/intern/bpy_rna_driver.c @@ -34,9 +34,6 @@ #include "bpy_rna_driver.h" /* own include */ -/** - * A version of #driver_get_variable_value which returns a PyObject. - */ PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar) { PyObject *driver_arg = NULL; diff --git a/source/blender/python/intern/bpy_rna_driver.h b/source/blender/python/intern/bpy_rna_driver.h index cc2c4550870..e34c7e4597c 100644 --- a/source/blender/python/intern/bpy_rna_driver.h +++ b/source/blender/python/intern/bpy_rna_driver.h @@ -28,6 +28,9 @@ struct PathResolvedRNA; extern "C" { #endif +/** + * A version of #driver_get_variable_value which returns a #PyObject. + */ PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar); PyObject *pyrna_driver_self_from_anim_rna(struct PathResolvedRNA *anim_rna); |