38#include "RNA_prototypes.hh"
45 PyErr_Format(PyExc_TypeError,
46 "Expected a StructRNA of type BlendData, not %.200s",
47 Py_TYPE(obj)->tp_name);
52 if (!(pyrna->
ptr && pyrna->
ptr->type == &RNA_BlendData && pyrna->
ptr->data)) {
53 PyErr_Format(PyExc_TypeError,
54 "Expected a StructRNA of type BlendData, not %.200s",
55 Py_TYPE(pyrna)->tp_name);
58 return static_cast<Main *
>(pyrna->
ptr->data);
77 return int(*((
ushort *)&idcode));
93 if (
data->types_bitmap) {
114 if ((set = PyDict_GetItem(
data->user_map, key)) ==
nullptr) {
116 if (
data->is_subset) {
120 set = PySet_New(
nullptr);
121 PyDict_SetItem(
data->user_map, key, set);
126 if (
data->py_id_curr ==
nullptr) {
130 PySet_Add(set,
data->py_id_curr);
141 ".. method:: user_map(*, subset=None, key_types=None, value_types=None)\n"
143 " Returns a mapping of all ID data-blocks in current ``bpy.data`` to a set of all "
144 "data-blocks using them.\n"
146 " For list of valid set members for key_types & value_types, see: "
147 ":class:`bpy.types.KeyingSetPath.id_type`.\n"
149 " :arg subset: When passed, only these data-blocks and their users will be "
150 "included as keys/values in the map.\n"
151 " :type subset: Sequence[:class:`bpy.types.ID`]\n"
152 " :arg key_types: Filter the keys mapped by ID types.\n"
153 " :type key_types: set[str]\n"
154 " :arg value_types: Filter the values in the set by ID types.\n"
155 " :type value_types: set[str]\n"
156 " :return: dictionary that maps data-blocks ID's to their users.\n"
157 " :rtype: dict[:class:`bpy.types.ID`, set[:class:`bpy.types.ID`]]\n");
168 PyObject *subset =
nullptr;
170 PyObject *key_types =
nullptr;
171 PyObject *val_types =
nullptr;
175 PyObject *
ret =
nullptr;
179 static const char *_keywords[] = {
"subset",
"key_types",
"value_types",
nullptr};
180 static _PyArg_Parser _parser = {
190 if (!_PyArg_ParseTupleAndKeywordsFast(
191 args, kwds, &_parser, &subset, &PySet_Type, &key_types, &PySet_Type, &val_types))
199 if (key_types_bitmap ==
nullptr) {
207 if (val_types_bitmap ==
nullptr) {
213 PyObject *subset_fast = PySequence_Fast(subset,
"user_map");
214 if (subset_fast ==
nullptr) {
218 PyObject **subset_array = PySequence_Fast_ITEMS(subset_fast);
219 Py_ssize_t subset_len = PySequence_Fast_GET_SIZE(subset_fast);
221 data_cb.
user_map = _PyDict_NewPresized(subset_len);
223 for (; subset_len; subset_array++, subset_len--) {
226 PyErr_Format(PyExc_TypeError,
227 "Expected an ID type in `subset` iterable, not %.200s",
228 Py_TYPE(*subset_array)->tp_name);
229 Py_DECREF(subset_fast);
234 if (!PyDict_Contains(data_cb.
user_map, *subset_array)) {
235 PyObject *set = PySet_New(
nullptr);
236 PyDict_SetItem(data_cb.
user_map, *subset_array, set);
240 Py_DECREF(subset_fast);
251 if (key_types_bitmap ==
nullptr && val_types_bitmap !=
nullptr) {
259 (key_types_bitmap ==
nullptr ||
id_check_type(
id, key_types_bitmap)) &&
262 (val_types_bitmap ==
nullptr || key_types_bitmap !=
nullptr))
269 if ((set = PyDict_GetItem(data_cb.
user_map, key)) ==
nullptr) {
270 set = PySet_New(
nullptr);
271 PyDict_SetItem(data_cb.
user_map, key, set);
277 if (val_types_bitmap !=
nullptr && !
id_check_type(
id, val_types_bitmap)) {
297 if (key_types_bitmap !=
nullptr) {
300 if (val_types_bitmap !=
nullptr) {
327 const char *path_src)
330 PyObject *id_file_path_set =
data.id_file_path_set;
334 if (path_src && *path_src) {
336 PySet_Add(id_file_path_set, path);
346 PyObject *id_file_path_set =
data.id_file_path_set;
350 PySet_Add(id_file_path_set, path);
359 bpy_file_path_map_doc,
360 ".. method:: file_path_map(subset=None, key_types=None, include_libraries=False)\n"
362 " Returns a mapping of all ID data-blocks in current ``bpy.data`` to a set of all "
363 "file paths used by them.\n"
365 " For list of valid set members for key_types, see: "
366 ":class:`bpy.types.KeyingSetPath.id_type`.\n"
368 " :arg subset: When given, only these data-blocks and their used file paths "
369 "will be included as keys/values in the map.\n"
370 " :type subset: sequence\n"
371 " :arg key_types: When given, filter the keys mapped by ID types. Ignored if ``subset`` is "
373 " :type key_types: set of strings\n"
374 " :arg include_libraries: Include library file paths of linked data. False by default.\n"
375 " :type include_libraries: bool\n"
376 " :return: dictionary of :class:`bpy.types.ID` instances, with sets of file path "
377 "strings as their values.\n"
386 PyObject *subset =
nullptr;
388 PyObject *key_types =
nullptr;
389 PyObject *include_libraries =
nullptr;
392 PyObject *
ret =
nullptr;
397 static const char *_keywords[] = {
"subset",
"key_types",
"include_libraries",
nullptr};
398 static _PyArg_Parser _parser = {
408 if (!_PyArg_ParseTupleAndKeywordsFast(args,
423 if (key_types_bitmap ==
nullptr) {
428 bpath_data.
bmain = bmain;
432 bpath_data.
user_data = &filepathmap_data;
437 PyObject *subset_fast = PySequence_Fast(subset,
"user_map");
438 if (subset_fast ==
nullptr) {
442 PyObject **subset_array = PySequence_Fast_ITEMS(subset_fast);
443 Py_ssize_t subset_len = PySequence_Fast_GET_SIZE(subset_fast);
445 filepathmap_data.
file_path_map = _PyDict_NewPresized(subset_len);
446 for (; subset_len; subset_array++, subset_len--) {
447 if (PyDict_Contains(filepathmap_data.
file_path_map, *subset_array)) {
453 PyErr_Format(PyExc_TypeError,
454 "Expected an ID type in `subset` iterable, not %.200s",
455 Py_TYPE(*subset_array)->tp_name);
456 Py_DECREF(subset_fast);
466 filepathmap_data.
id = id;
469 Py_DECREF(subset_fast);
479 if (key_types_bitmap && !
id_check_type(
id, key_types_bitmap)) {
489 filepathmap_data.
id = id;
500 if (key_types_bitmap !=
nullptr) {
509 bpy_batch_remove_doc,
510 ".. method:: batch_remove(ids)\n"
512 " Remove (delete) several IDs at once.\n"
514 " Note that this function is quicker than individual calls to :func:`remove()` "
515 "(from :class:`bpy.types.BlendData`\n"
516 " ID collections), but less safe/versatile (it can break Blender, e.g. by removing "
519 " :arg ids: Sequence of IDs (types can be mixed).\n"
520 " :type ids: Sequence[:class:`bpy.types.ID`]\n");
528 PyObject *ids =
nullptr;
530 static const char *_keywords[] = {
"ids",
nullptr};
531 static _PyArg_Parser _parser = {
538 if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &ids)) {
546 PyObject *ids_fast = PySequence_Fast(ids,
"batch_remove");
547 if (ids_fast ==
nullptr) {
551 PyObject **ids_array = PySequence_Fast_ITEMS(ids_fast);
552 Py_ssize_t ids_len = PySequence_Fast_GET_SIZE(ids_fast);
554 for (; ids_len; ids_array++, ids_len--) {
558 PyExc_TypeError,
"Expected an ID type, not %.200s", Py_TYPE(*ids_array)->tp_name);
563 ids_to_delete.
add(
id);
576 bpy_orphans_purge_doc,
577 ".. method:: orphans_purge()\n"
579 " Remove (delete) all IDs with no user.\n"
581 " :arg do_local_ids: Include unused local IDs in the deletion, defaults to True\n"
582 " :type do_local_ids: bool, optional\n"
583 " :arg do_linked_ids: Include unused linked IDs in the deletion, defaults to True\n"
584 " :type do_linked_ids: bool, optional\n"
585 " :arg do_recursive: Recursively check for unused IDs, ensuring no orphaned one "
586 "remain after a single run of that function, defaults to False\n"
587 " :type do_recursive: bool, optional\n"
588 " :return: The number of deleted IDs.\n");
601 static const char *_keywords[] = {
"do_local_ids",
"do_linked_ids",
"do_recursive",
nullptr};
602 static _PyArg_Parser _parser = {
612 if (!_PyArg_ParseTupleAndKeywordsFast(args,
629 return PyLong_FromSize_t(0);
636 return PyLong_FromSize_t(num_datablocks_deleted);
641# pragma clang diagnostic push
642# pragma clang diagnostic ignored "-Wcast-function-type"
644# pragma GCC diagnostic push
645# pragma GCC diagnostic ignored "-Wcast-function-type"
652 METH_VARARGS | METH_KEYWORDS,
658 METH_VARARGS | METH_KEYWORDS,
659 bpy_file_path_map_doc,
664 METH_VARARGS | METH_KEYWORDS,
665 bpy_batch_remove_doc,
670 METH_VARARGS | METH_KEYWORDS,
671 bpy_orphans_purge_doc,
676# pragma clang diagnostic pop
678# pragma GCC diagnostic pop
void BKE_bpath_foreach_path_id(BPathForeachPathData *bpath_data, ID *id)
@ BKE_BPATH_TRAVERSE_SKIP_WEAK_REFERENCES
@ BKE_BPATH_FOREACH_PATH_SKIP_PACKED
void size_t BKE_id_multi_tagged_delete(Main *bmain) ATTR_NONNULL()
size_t BKE_id_multi_delete(Main *bmain, blender::Set< ID * > &ids_to_delete)
LibraryForeachIDCallbackFlag
@ IDWALK_CB_EMBEDDED_NOT_OWNING
void BKE_library_foreach_ID_link(Main *bmain, ID *id, blender::FunctionRef< LibraryIDLinkCallback > callback, void *user_data, LibraryForeachIDFlag flag)
#define FOREACH_MAIN_LISTBASE_ID_END
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id)
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb)
#define BLI_BITMAP_TEST_BOOL(_bitmap, _index)
ID and Library types, which are fundamental for SDNA.
Read Guarded memory(de)allocation.
BMesh const char void * data
#define PYRNA_STRUCT_CHECK_OBJ(obj)
#define BPy_StructRNA_Check(v)
static bool id_check_type(const ID *id, const BLI_bitmap *types_bitmap)
static PyObject * bpy_orphans_purge(PyObject *self, PyObject *args, PyObject *kwds)
static int id_code_as_index(const short idcode)
static void foreach_id_file_path_map(BPathForeachPathData &bpath_data)
PyDoc_STRVAR(bpy_user_map_doc, ".. method:: user_map(*, subset=None, key_types=None, value_types=None)\n" "\n" " Returns a mapping of all ID data-blocks in current ``bpy.data`` to a set of all " "data-blocks using them.\n" "\n" " For list of valid set members for key_types & value_types, see: " ":class:`bpy.types.KeyingSetPath.id_type`.\n" "\n" " :arg subset: When passed, only these data-blocks and their users will be " "included as keys/values in the map.\n" " :type subset: Sequence[:class:`bpy.types.ID`]\n" " :arg key_types: Filter the keys mapped by ID types.\n" " :type key_types: set[str]\n" " :arg value_types: Filter the values in the set by ID types.\n" " :type value_types: set[str]\n" " :return: dictionary that maps data-blocks ID's to their users.\n" " :rtype: dict[:class:`bpy.types.ID`, set[:class:`bpy.types.ID`]]\n")
static bool foreach_id_file_path_map_callback(BPathForeachPathData *bpath_data, char *, size_t, const char *path_src)
static PyObject * bpy_file_path_map(PyObject *self, PyObject *args, PyObject *kwds)
PyMethodDef BPY_rna_id_collection_batch_remove_method_def
static int foreach_libblock_id_user_map_callback(LibraryIDLinkCallbackData *cb_data)
static Main * pyrna_bmain_FromPyObject(PyObject *obj)
static PyObject * bpy_user_map(PyObject *self, PyObject *args, PyObject *kwds)
PyMethodDef BPY_rna_id_collection_orphans_purge_method_def
PyMethodDef BPY_rna_id_collection_file_path_map_method_def
static PyObject * bpy_batch_remove(PyObject *self, PyObject *args, PyObject *kwds)
PyMethodDef BPY_rna_id_collection_user_map_method_def
#define ID_IS_LINKED(_id)
PyObject * pyrna_id_CreatePyObject(ID *id)
bool pyrna_id_FromPyObject(PyObject *obj, ID **id)
void BKE_lib_query_unused_ids_tag(Main *bmain, const int tag, LibQueryUnusedIDsData ¶meters)
void MEM_freeN(void *vmemh)
static void error(const char *str)
BLI_bitmap * pyrna_enum_bitmap_from_set(const EnumPropertyItem *items, PyObject *value, int type_size, bool type_convert_sign, int bitmap_size, const char *error_prefix)
PyObject * PyC_UnicodeFromBytes(const char *str)
int PyC_ParseBool(PyObject *o, void *p)
header-only compatibility defines.
#define PY_ARG_PARSER_HEAD_COMPAT()
const EnumPropertyItem rna_enum_id_type_items[]
BPathForeachPathFunctionCallback callback_function
PyObject_HEAD std::optional< PointerRNA > ptr
PyObject * id_file_path_set
BLI_bitmap * types_bitmap
std::array< int, INDEX_ID_MAX > num_total
LibraryForeachIDCallbackFlag cb_flag
void WM_main_add_notifier(uint type, void *reference)