diff options
author | Bastien Montagne <bastien@blender.org> | 2021-11-23 14:12:28 +0300 |
---|---|---|
committer | Bastien Montagne <bastien@blender.org> | 2021-11-30 17:02:53 +0300 |
commit | 0704570721b71ef108e2e13bc2ee10c120d38b83 (patch) | |
tree | 9dbb91815a91e9d49b8c51ffbc495fd120c0a470 /source/blender/python/intern/bpy_library_load.c | |
parent | 8cf0d15b6021280b70b8cc51016e9754f67dd13e (diff) |
LibLink/Append: Port `bpy.data.libraries.load` to new `BKE_blendfile_link_append` module.
Note that this fully replaces the 'PyCapsule' storage of linked/appended items
in the python API code by the generic storage of items in the
`BlendfileLinkAppendContext` data.
Maniphest Tasks: T91414
Differential Revision: https://developer.blender.org/D13331
Diffstat (limited to 'source/blender/python/intern/bpy_library_load.c')
-rw-r--r-- | source/blender/python/intern/bpy_library_load.c | 249 |
1 files changed, 134 insertions, 115 deletions
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; } |