Blender  V2.93
bpy_library_load.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
28 #include <Python.h>
29 #include <stddef.h>
30 
31 #include "BLI_ghash.h"
32 #include "BLI_linklist.h"
33 #include "BLI_path_util.h"
34 #include "BLI_string.h"
35 #include "BLI_utildefines.h"
36 
37 #include "BKE_context.h"
38 #include "BKE_idtype.h"
39 #include "BKE_lib_id.h"
40 #include "BKE_main.h"
41 #include "BKE_report.h"
42 
43 #include "DNA_space_types.h" /* FILE_LINK, FILE_RELPATH */
44 
45 #include "BLO_readfile.h"
46 
47 #include "MEM_guardedalloc.h"
48 
49 #include "bpy_capi_utils.h"
50 #include "bpy_library.h"
51 
52 #include "../generic/py_capi_utils.h"
53 #include "../generic/python_utildefines.h"
54 
55 /* nifty feature. swap out strings for RNA data */
56 #define USE_RNA_DATABLOCKS
57 
58 #ifdef USE_RNA_DATABLOCKS
59 # include "RNA_access.h"
60 # include "bpy_rna.h"
61 #endif
62 
63 typedef struct {
64  PyObject_HEAD /* required python macro */
65  /* collection iterator specific parts */
66  char relpath[FILE_MAX];
67  char abspath[FILE_MAX]; /* absolute path */
69  int flag;
70  PyObject *dict;
71  /* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries.
72  * Defaults to #G.main, Otherwise use a temporary #Main when `bmain_is_temp` is true. */
75 } BPy_Library;
76 
77 static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kwds);
78 static PyObject *bpy_lib_enter(BPy_Library *self);
79 static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *args);
80 static PyObject *bpy_lib_dir(BPy_Library *self);
81 
82 static PyMethodDef bpy_lib_methods[] = {
83  {"__enter__", (PyCFunction)bpy_lib_enter, METH_NOARGS},
84  {"__exit__", (PyCFunction)bpy_lib_exit, METH_VARARGS},
85  {"__dir__", (PyCFunction)bpy_lib_dir, METH_NOARGS},
86  {NULL} /* sentinel */
87 };
88 
89 static void bpy_lib_dealloc(BPy_Library *self)
90 {
91  Py_XDECREF(self->dict);
92  Py_TYPE(self)->tp_free(self);
93 }
94 
95 static PyTypeObject bpy_lib_Type = {
96  PyVarObject_HEAD_INIT(NULL, 0) "bpy_lib", /* tp_name */
97  sizeof(BPy_Library), /* tp_basicsize */
98  0, /* tp_itemsize */
99  /* methods */
100  (destructor)bpy_lib_dealloc, /* tp_dealloc */
101  0, /* tp_vectorcall_offset */
102  NULL, /* getattrfunc tp_getattr; */
103  NULL, /* setattrfunc tp_setattr; */
104  NULL,
105  /* tp_compare */ /* DEPRECATED in python 3.0! */
106  NULL, /* tp_repr */
107 
108  /* Method suites for standard classes */
109 
110  NULL, /* PyNumberMethods *tp_as_number; */
111  NULL, /* PySequenceMethods *tp_as_sequence; */
112  NULL, /* PyMappingMethods *tp_as_mapping; */
113 
114  /* More standard operations (here for binary compatibility) */
115 
116  NULL, /* hashfunc tp_hash; */
117  NULL, /* ternaryfunc tp_call; */
118  NULL, /* reprfunc tp_str; */
119 
120  /* will only use these if this is a subtype of a py class */
121  PyObject_GenericGetAttr, /* getattrofunc tp_getattro; */
122  NULL, /* setattrofunc tp_setattro; */
123 
124  /* Functions to access object as input/output buffer */
125  NULL, /* PyBufferProcs *tp_as_buffer; */
126 
127  /*** Flags to define presence of optional/expanded features ***/
128  Py_TPFLAGS_DEFAULT, /* long tp_flags; */
129 
130  NULL, /* char *tp_doc; Documentation string */
131  /*** Assigned meaning in release 2.0 ***/
132  /* call function for all accessible objects */
133  NULL, /* traverseproc tp_traverse; */
134 
135  /* delete references to contained objects */
136  NULL, /* inquiry tp_clear; */
137 
138  /*** Assigned meaning in release 2.1 ***/
139  /*** rich comparisons (subclassed) ***/
140  NULL, /* richcmpfunc tp_richcompare; */
141 
142  /*** weak reference enabler ***/
143  0,
144  /*** Added in release 2.2 ***/
145  /* Iterators */
146  NULL, /* getiterfunc tp_iter; */
147  NULL, /* iternextfunc tp_iternext; */
148 
149  /*** Attribute descriptor and subclassing stuff ***/
150  bpy_lib_methods, /* struct PyMethodDef *tp_methods; */
151  NULL, /* struct PyMemberDef *tp_members; */
152  NULL, /* struct PyGetSetDef *tp_getset; */
153  NULL, /* struct _typeobject *tp_base; */
154  NULL, /* PyObject *tp_dict; */
155  NULL, /* descrgetfunc tp_descr_get; */
156  NULL, /* descrsetfunc tp_descr_set; */
157  offsetof(BPy_Library, dict), /* long tp_dictoffset; */
158  NULL, /* initproc tp_init; */
159  NULL, /* allocfunc tp_alloc; */
160  NULL, /* newfunc tp_new; */
161  /* Low-level free-memory routine */
162  NULL, /* freefunc tp_free; */
163  /* For PyObject_IS_GC */
164  NULL, /* inquiry tp_is_gc; */
165  NULL, /* PyObject *tp_bases; */
166  /* method resolution order */
167  NULL, /* PyObject *tp_mro; */
168  NULL, /* PyObject *tp_cache; */
169  NULL, /* PyObject *tp_subclasses; */
170  NULL, /* PyObject *tp_weaklist; */
171  NULL,
172 };
173 
175  bpy_lib_load_doc,
176  ".. method:: load(filepath, link=False, relative=False, assets_only=False)\n"
177  "\n"
178  " Returns a context manager which exposes 2 library objects on entering.\n"
179  " Each object has attributes matching bpy.data which are lists of strings to be linked.\n"
180  "\n"
181  " :arg filepath: The path to a blend file.\n"
182  " :type filepath: string\n"
183  " :arg link: When False reference to the original file is lost.\n"
184  " :type link: bool\n"
185  " :arg relative: When True the path is stored relative to the open blend file.\n"
186  " :type relative: bool\n"
187  " :arg assets_only: If True, only list data-blocks marked as assets.\n"
188  " :type assets_only: bool\n");
189 static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kw)
190 {
191  Main *bmain_base = CTX_data_main(BPY_context_get());
192  Main *bmain = self->ptr.data; /* Typically #G_MAIN */
193  BPy_Library *ret;
194  const char *filename = NULL;
195  bool is_rel = false, is_link = false, use_assets_only = false;
196 
197  static const char *_keywords[] = {"filepath", "link", "relative", "assets_only", NULL};
198  static _PyArg_Parser _parser = {"s|O&O&O&:load", _keywords, 0};
199  if (!_PyArg_ParseTupleAndKeywordsFast(args,
200  kw,
201  &_parser,
202  &filename,
204  &is_link,
206  &is_rel,
208  &use_assets_only)) {
209  return NULL;
210  }
211 
212  ret = PyObject_New(BPy_Library, &bpy_lib_Type);
213 
214  BLI_strncpy(ret->relpath, filename, sizeof(ret->relpath));
215  BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath));
216  BLI_path_abs(ret->abspath, BKE_main_blendfile_path(bmain));
217 
218  ret->bmain = bmain;
219  ret->bmain_is_temp = (bmain != bmain_base);
220 
221  ret->blo_handle = NULL;
222  ret->flag = ((is_link ? FILE_LINK : 0) | (is_rel ? FILE_RELPATH : 0) |
223  (use_assets_only ? FILE_ASSETS_ONLY : 0));
224 
225  ret->dict = _PyDict_NewPresized(INDEX_ID_MAX);
226 
227  return (PyObject *)ret;
228 }
229 
230 static PyObject *_bpy_names(BPy_Library *self, int blocktype)
231 {
232  PyObject *list;
233  LinkNode *l, *names;
234  int totnames;
235 
237  self->blo_handle, blocktype, (self->flag & FILE_ASSETS_ONLY) != 0, &totnames);
238  list = PyList_New(totnames);
239 
240  if (names) {
241  int counter = 0;
242  for (l = names; l; l = l->next) {
243  PyList_SET_ITEM(list, counter, PyUnicode_FromString((char *)l->link));
244  counter++;
245  }
246  BLI_linklist_freeN(names); /* free linklist *and* each node's data */
247  }
248 
249  return list;
250 }
251 
252 static PyObject *bpy_lib_enter(BPy_Library *self)
253 {
254  PyObject *ret;
255  BPy_Library *self_from;
256  PyObject *from_dict = _PyDict_NewPresized(INDEX_ID_MAX);
257  ReportList reports;
258 
259  BKE_reports_init(&reports, RPT_STORE);
260 
261  self->blo_handle = BLO_blendhandle_from_file(self->abspath, &reports);
262 
263  if (self->blo_handle == NULL) {
264  if (BPy_reports_to_error(&reports, PyExc_IOError, true) != -1) {
265  PyErr_Format(PyExc_IOError, "load: %s failed to open blend file", self->abspath);
266  }
267  return NULL;
268  }
269 
270  int i = 0, code;
271  while ((code = BKE_idtype_idcode_iter_step(&i))) {
272  if (BKE_idtype_idcode_is_linkable(code)) {
273  const char *name_plural = BKE_idtype_idcode_to_name_plural(code);
274  PyObject *str = PyUnicode_FromString(name_plural);
275  PyObject *item;
276 
277  PyDict_SetItem(self->dict, str, item = PyList_New(0));
278  Py_DECREF(item);
279  PyDict_SetItem(from_dict, str, item = _bpy_names(self, code));
280  Py_DECREF(item);
281 
282  Py_DECREF(str);
283  }
284  }
285 
286  /* create a dummy */
287  self_from = PyObject_New(BPy_Library, &bpy_lib_Type);
288  BLI_strncpy(self_from->relpath, self->relpath, sizeof(self_from->relpath));
289  BLI_strncpy(self_from->abspath, self->abspath, sizeof(self_from->abspath));
290 
291  self_from->blo_handle = NULL;
292  self_from->flag = 0;
293  self_from->dict = from_dict; /* owns the dict */
294 
295  /* return pair */
296  ret = PyTuple_New(2);
297  PyTuple_SET_ITEMS(ret, (PyObject *)self_from, (PyObject *)self);
298  Py_INCREF(self);
299 
300  BKE_reports_clear(&reports);
301 
302  return ret;
303 }
304 
306  const char *name_plural,
307  const char *idname)
308 {
309  PyObject *exc, *val, *tb;
310  PyErr_Fetch(&exc, &val, &tb);
311  if (PyErr_WarnFormat(PyExc_UserWarning,
312  1,
313  "load: '%s' does not contain %s[\"%s\"]",
314  self->abspath,
315  name_plural,
316  idname)) {
317  /* Spurious errors can appear at shutdown */
318  if (PyErr_ExceptionMatches(PyExc_Warning)) {
319  PyErr_WriteUnraisable((PyObject *)self);
320  }
321  }
322  PyErr_Restore(exc, val, tb);
323 }
324 
325 static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item)
326 {
327  PyObject *exc, *val, *tb;
328  PyErr_Fetch(&exc, &val, &tb);
329  if (PyErr_WarnFormat(PyExc_UserWarning,
330  1,
331  "load: '%s' expected a string type, not a %.200s",
332  self->abspath,
333  Py_TYPE(item)->tp_name)) {
334  /* Spurious errors can appear at shutdown */
335  if (PyErr_ExceptionMatches(PyExc_Warning)) {
336  PyErr_WriteUnraisable((PyObject *)self);
337  }
338  }
339  PyErr_Restore(exc, val, tb);
340 }
341 
342 static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
343 {
344  Main *bmain = self->bmain;
345  Main *mainl = NULL;
346  const int err = 0;
347  const bool do_append = ((self->flag & FILE_LINK) == 0);
348 
350 
351  /* here appending/linking starts */
352  const int id_tag_extra = self->bmain_is_temp ? LIB_TAG_TEMP_MAIN : 0;
353  struct LibraryLink_Params liblink_params;
354  BLO_library_link_params_init(&liblink_params, bmain, self->flag, id_tag_extra);
355 
356  mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params);
357 
358  {
359  int idcode_step = 0, idcode;
360  while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
361  if (BKE_idtype_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
362  const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
363  PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
364  // printf("lib: %s\n", name_plural);
365  if (ls && PyList_Check(ls)) {
366  /* loop */
367  const Py_ssize_t size = PyList_GET_SIZE(ls);
368  Py_ssize_t i;
369 
370  for (i = 0; i < size; i++) {
371  PyObject *item_src = PyList_GET_ITEM(ls, i);
372  PyObject *item_dst; /* must be set below */
373  const char *item_idname = PyUnicode_AsUTF8(item_src);
374 
375  // printf(" %s\n", item_idname);
376 
377  if (item_idname) {
379  mainl, &(self->blo_handle), idcode, item_idname, &liblink_params);
380  if (id) {
381 
382  if (self->bmain_is_temp) {
383  /* If this fails, #LibraryLink_Params.id_tag_extra is not being applied. */
385  }
386 
387 #ifdef USE_RNA_DATABLOCKS
388  /* swap name for pointer to the id */
389  item_dst = PyCapsule_New((void *)id, NULL, NULL);
390 #else
391  /* leave as is */
392  continue;
393 #endif
394  }
395  else {
396  bpy_lib_exit_warn_idname(self, name_plural, item_idname);
397  /* just warn for now */
398  /* err = -1; */
399  item_dst = Py_INCREF_RET(Py_None);
400  }
401 
402  /* ID or None */
403  }
404  else {
405  /* XXX, could complain about this */
406  bpy_lib_exit_warn_type(self, item_src);
407  PyErr_Clear();
408  item_dst = Py_INCREF_RET(Py_None);
409  }
410 
411  /* item_dst must be new or already incref'd */
412  Py_DECREF(item_src);
413  PyList_SET_ITEM(ls, i, item_dst);
414  }
415  }
416  }
417  }
418  }
419 
420  if (err == -1) {
421  /* exception raised above, XXX, this leaks some memory */
422  BLO_blendhandle_close(self->blo_handle);
423  self->blo_handle = NULL;
425  return NULL;
426  }
427 
428  Library *lib = mainl->curlib; /* newly added lib, assign before append end */
429  BLO_library_link_end(mainl, &(self->blo_handle), &liblink_params);
430  BLO_blendhandle_close(self->blo_handle);
431  self->blo_handle = NULL;
432 
433  GHash *old_to_new_ids = BLI_ghash_ptr_new(__func__);
434 
435  /* copied from wm_operator.c */
436  {
437  /* mark all library linked objects to be updated */
439 
440  /* append, rather than linking */
441  if (do_append) {
442  BKE_library_make_local(bmain, lib, old_to_new_ids, true, false);
443  }
444  }
445 
447 
448  /* finally swap the capsules for real bpy objects
449  * important since BLO_library_append_end initializes NodeTree types used by srna->refine */
450 #ifdef USE_RNA_DATABLOCKS
451  {
452  int idcode_step = 0, idcode;
453  while ((idcode = BKE_idtype_idcode_iter_step(&idcode_step))) {
454  if (BKE_idtype_idcode_is_linkable(idcode) && (idcode != ID_WS || do_append)) {
455  const char *name_plural = BKE_idtype_idcode_to_name_plural(idcode);
456  PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
457  if (ls && PyList_Check(ls)) {
458  const Py_ssize_t size = PyList_GET_SIZE(ls);
459  Py_ssize_t i;
460  PyObject *item;
461 
462  for (i = 0; i < size; i++) {
463  item = PyList_GET_ITEM(ls, i);
464  if (PyCapsule_CheckExact(item)) {
465  PointerRNA id_ptr;
466  ID *id;
467 
468  id = PyCapsule_GetPointer(item, NULL);
469  id = BLI_ghash_lookup_default(old_to_new_ids, id, id);
470  Py_DECREF(item);
471 
472  RNA_id_pointer_create(id, &id_ptr);
473  item = pyrna_struct_CreatePyObject(&id_ptr);
474  PyList_SET_ITEM(ls, i, item);
475  }
476  }
477  }
478  }
479  }
480  }
481 #endif /* USE_RNA_DATABLOCKS */
482 
483  BLI_ghash_free(old_to_new_ids, NULL, NULL);
484  Py_RETURN_NONE;
485 }
486 
487 static PyObject *bpy_lib_dir(BPy_Library *self)
488 {
489  return PyDict_Keys(self->dict);
490 }
491 
493  "load",
494  (PyCFunction)bpy_lib_load,
495  METH_VARARGS | METH_KEYWORDS,
496  bpy_lib_load_doc,
497 };
498 
500 {
501  if (PyType_Ready(&bpy_lib_Type) < 0) {
502  return -1;
503  }
504 
505  return 0;
506 }
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
const char * BKE_idtype_idcode_to_name_plural(const short idcode)
Definition: idtype.c:182
bool BKE_idtype_idcode_is_linkable(const short idcode)
Definition: idtype.c:232
short BKE_idtype_idcode_iter_step(int *index)
Definition: idtype.c:472
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
Definition: lib_id.c:923
void BKE_main_lib_objects_recalc_all(struct Main *bmain)
Definition: lib_id.c:997
void BKE_library_make_local(struct Main *bmain, const struct Library *lib, struct GHash *old_to_new_ids, const bool untagged_only, const bool set_fake)
const char * BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL()
void BKE_reports_clear(ReportList *reports)
Definition: report.c:84
void BKE_reports_init(ReportList *reports, int flag)
Definition: report.c:66
#define BLI_assert(a)
Definition: BLI_assert.h:58
void * BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:813
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
#define FILE_MAX
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL()
Definition: path_util.c:1016
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define UNUSED(x)
external readfile function prototypes.
void BLO_library_link_params_init(struct LibraryLink_Params *params, struct Main *bmain, const int flag, const int id_tag_extra)
Definition: readfile.c:5069
struct ID * BLO_library_link_named_part(struct Main *mainl, BlendHandle **bh, const short idcode, const char *name, const struct LibraryLink_Params *params)
Definition: readfile.c:4989
struct BlendHandle BlendHandle
Definition: BLO_readfile.h:49
struct Main * BLO_library_link_begin(BlendHandle **bh, const char *filepath, const struct LibraryLink_Params *params)
Definition: readfile.c:5109
void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, const struct LibraryLink_Params *params)
Definition: readfile.c:5258
struct LinkNode * BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, const bool use_assets_only, int *r_tot_names)
BlendHandle * BLO_blendhandle_from_file(const char *filepath, struct ReportList *reports)
Definition: readblenentry.c:71
void BLO_blendhandle_close(BlendHandle *bh)
@ LIB_TAG_TEMP_MAIN
Definition: DNA_ID.h:585
@ LIB_TAG_PRE_EXISTING
Definition: DNA_ID.h:556
@ INDEX_ID_MAX
Definition: DNA_ID.h:859
@ ID_WS
Definition: DNA_ID_enums.h:91
@ FILE_RELPATH
@ FILE_LINK
@ FILE_ASSETS_ONLY
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMLoop * l
short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool clear)
struct bContext * BPY_context_get(void)
PyObject * self
Definition: bpy_driver.c:185
PyMethodDef BPY_library_load_method_def
static void bpy_lib_dealloc(BPy_Library *self)
static PyMethodDef bpy_lib_methods[]
PyDoc_STRVAR(bpy_lib_load_doc, ".. method:: load(filepath, link=False, relative=False, assets_only=False)\n" "\n" " Returns a context manager which exposes 2 library objects on entering.\n" " Each object has attributes matching bpy.data which are lists of strings to be linked.\n" "\n" " :arg filepath: The path to a blend file.\n" " :type filepath: string\n" " :arg link: When False reference to the original file is lost.\n" " :type link: bool\n" " :arg relative: When True the path is stored relative to the open blend file.\n" " :type relative: bool\n" " :arg assets_only: If True, only list data-blocks marked as assets.\n" " :type assets_only: bool\n")
static PyObject * bpy_lib_enter(BPy_Library *self)
static PyObject * bpy_lib_exit(BPy_Library *self, PyObject *args)
static PyObject * bpy_lib_dir(BPy_Library *self)
int BPY_library_load_type_ready(void)
static PyObject * _bpy_names(BPy_Library *self, int blocktype)
static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item)
static PyTypeObject bpy_lib_Type
static PyObject * bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kwds)
static void bpy_lib_exit_warn_idname(BPy_Library *self, const char *name_plural, const char *idname)
PyObject * pyrna_struct_CreatePyObject(PointerRNA *ptr)
Definition: bpy_rna.c:7469
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
DRWShaderLibrary * lib
#define str(s)
static FT_Error err
Definition: freetypefont.c:52
static char ** names
Definition: makesdna.c:162
int PyC_ParseBool(PyObject *o, void *p)
#define PyTuple_SET_ITEMS(op_arg,...)
return ret
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:122
struct BMLoop * next
Definition: bmesh_class.h:245
BlendHandle * blo_handle
char abspath[FILE_MAX]
PyObject * dict
PyObject_HEAD char relpath[FILE_MAX]
Definition: DNA_ID.h:273
int tag
Definition: DNA_ID.h:292
Definition: BKE_main.h:116
struct Library * curlib
Definition: BKE_main.h:145