Expose batch IDs deletion in python API.
authorBastien Montagne <montagne29@wanadoo.fr>
Wed, 16 Jan 2019 10:58:11 +0000 (11:58 +0100)
committerBastien Montagne <montagne29@wanadoo.fr>
Wed, 16 Jan 2019 11:02:37 +0000 (12:02 +0100)
Follow-up to previous commit.

release/scripts/modules/bpy_types.py
source/blender/python/intern/bpy_library_write.c
source/blender/python/intern/bpy_rna_id_collection.c

index 47f1320..f12b259 100644 (file)
@@ -28,6 +28,7 @@ StructMetaPropGroup = bpy_types.bpy_struct_meta_idprop
 bpy_types.BlendDataLibraries.load = _bpy._library_load
 bpy_types.BlendDataLibraries.write = _bpy._library_write
 bpy_types.BlendData.user_map = _bpy._rna_id_collection_user_map
+bpy_types.BlendData.batch_remove = _bpy._rna_id_collection_batch_remove
 
 
 class Context(StructRNA):
index 07a81a3..69dcfdb 100644 (file)
@@ -134,7 +134,7 @@ static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject
 
                        if (!pyrna_id_FromPyObject(key, &id_store->id)) {
                                PyErr_Format(PyExc_TypeError,
-                                            "Expected and ID type, not %.200s",
+                                            "Expected an ID type, not %.200s",
                                             Py_TYPE(key)->tp_name);
                                ret = NULL;
                                goto finally;
index d2d08a3..3fc12d4 100644 (file)
@@ -35,6 +35,7 @@
 #include "BLI_bitmap.h"
 
 #include "BKE_global.h"
+#include "BKE_library.h"
 #include "BKE_library_query.h"
 #include "BKE_main.h"
 
@@ -289,6 +290,79 @@ error:
 
 }
 
+PyDoc_STRVAR(bpy_batch_remove_doc,
+".. method:: batch_remove(ids=(id1, id2, ...))\n"
+"\n"
+"   Remove (delete) several IDs at once.\n"
+"\n"
+"   WARNING: Considered experimental feature currently.\n"
+"\n"
+"   Note that this function is quicker than individual calls to :func:`remove()` (from :class:`bpy.types.BlendData`\n"
+"   ID collections), but less safe/versatile (it can break Blender, e.g. by removing all scenes...).\n"
+"\n"
+"   :arg ids: Iterables of IDs (types can be mixed).\n"
+"   :type subset: sequence\n"
+);
+static PyObject *bpy_batch_remove(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+{
+#if 0  /* If someone knows how to get a proper 'self' in that case... */
+       BPy_StructRNA *pyrna = (BPy_StructRNA *)self;
+       Main *bmain = pyrna->ptr.data;
+#else
+       Main *bmain = G_MAIN;  /* XXX Ugly, but should work! */
+#endif
+
+       PyObject *ids = NULL;
+
+       PyObject *ret = NULL;
+
+       static const char *_keywords[] = {"ids", NULL};
+       static _PyArg_Parser _parser = {"O:user_map", _keywords, 0};
+       if (!_PyArg_ParseTupleAndKeywordsFast(
+               args, kwds, &_parser,
+               &ids))
+       {
+               return ret;
+       }
+
+       if (ids) {
+               BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+
+               PyObject *ids_fast = PySequence_Fast(ids, "batch_remove");
+               if (ids_fast == NULL) {
+                       goto error;
+               }
+
+               PyObject **ids_array = PySequence_Fast_ITEMS(ids_fast);
+               Py_ssize_t ids_len = PySequence_Fast_GET_SIZE(ids_fast);
+
+               for (; ids_len; ids_array++, ids_len--) {
+                       ID *id;
+                       if (!pyrna_id_FromPyObject(*ids_array, &id)) {
+                               PyErr_Format(PyExc_TypeError,
+                                            "Expected an ID type, not %.200s",
+                                            Py_TYPE(*ids_array)->tp_name);
+                               Py_DECREF(ids_fast);
+                               goto error;
+                       }
+
+                       id->tag |= LIB_TAG_DOIT;
+               }
+               Py_DECREF(ids_fast);
+
+               BKE_id_multi_tagged_delete(bmain);
+       }
+       else {
+               goto error;
+       }
+
+       Py_INCREF(Py_None);
+       ret = Py_None;
+
+error:
+       return ret;
+}
+
 int BPY_rna_id_collection_module(PyObject *mod_par)
 {
        static PyMethodDef user_map = {
@@ -296,5 +370,10 @@ int BPY_rna_id_collection_module(PyObject *mod_par)
 
        PyModule_AddObject(mod_par, "_rna_id_collection_user_map", PyCFunction_New(&user_map, NULL));
 
+       static PyMethodDef batch_remove = {
+           "batch_remove", (PyCFunction)bpy_batch_remove, METH_VARARGS | METH_KEYWORDS, bpy_batch_remove_doc};
+
+       PyModule_AddObject(mod_par, "_rna_id_collection_batch_remove", PyCFunction_New(&batch_remove, NULL));
+
        return 0;
 }