Blender V2.61 - r43446

bpy_library.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * Contributor(s): Campbell Barton
00019  *
00020  * ***** END GPL LICENSE BLOCK *****
00021  */
00022 
00034 /* nifty feature. swap out strings for RNA data */
00035 #define USE_RNA_DATABLOCKS
00036 
00037 #include <Python.h>
00038 #include <stddef.h>
00039 
00040 #include "BLO_readfile.h"
00041 
00042 #include "BKE_global.h"
00043 #include "BKE_main.h"
00044 #include "BKE_library.h"
00045 #include "BKE_idcode.h"
00046 #include "BKE_report.h"
00047 #include "BKE_context.h"
00048 
00049 #include "BLI_utildefines.h"
00050 #include "BLI_string.h"
00051 #include "BLI_linklist.h"
00052 #include "BLI_path_util.h"
00053 #include "BLI_listbase.h"
00054 
00055 #include "DNA_space_types.h" /* FILE_LINK, FILE_RELPATH */
00056 
00057 #include "bpy_util.h"
00058 
00059 #ifdef USE_RNA_DATABLOCKS
00060 #  include "bpy_rna.h"
00061 #  include "RNA_access.h"
00062 #endif
00063 
00064 typedef struct {
00065     PyObject_HEAD /* required python macro   */
00066     /* collection iterator specific parts */
00067     char relpath[FILE_MAX];
00068     char abspath[FILE_MAX]; /* absolute path */
00069     BlendHandle *blo_handle;
00070     int flag;
00071     PyObject *dict;
00072 } BPy_Library;
00073 
00074 static PyObject *bpy_lib_load(PyObject *self, PyObject *args, PyObject *kwds);
00075 static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *args);
00076 static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *args);
00077 static PyObject *bpy_lib_dir(BPy_Library *self);
00078 
00079 static PyMethodDef bpy_lib_methods[] = {
00080     {"__enter__", (PyCFunction)bpy_lib_enter, METH_NOARGS},
00081     {"__exit__",  (PyCFunction)bpy_lib_exit,  METH_VARARGS},
00082     {"__dir__",   (PyCFunction)bpy_lib_dir,   METH_NOARGS},
00083     {NULL}           /* sentinel */
00084 };
00085 
00086 static void bpy_lib_dealloc(BPy_Library *self)
00087 {
00088     Py_XDECREF(self->dict);
00089     Py_TYPE(self)->tp_free(self);
00090 }
00091 
00092 
00093 static PyTypeObject bpy_lib_Type = {
00094     PyVarObject_HEAD_INIT(NULL, 0)
00095     "bpy_lib",      /* tp_name */
00096     sizeof(BPy_Library),            /* tp_basicsize */
00097     0,                          /* tp_itemsize */
00098     /* methods */
00099     (destructor)bpy_lib_dealloc,/* tp_dealloc */
00100     NULL,                       /* printfunc tp_print; */
00101     NULL,                       /* getattrfunc tp_getattr; */
00102     NULL,                       /* setattrfunc tp_setattr; */
00103     NULL,                       /* tp_compare */ /* DEPRECATED in python 3.0! */
00104     NULL,                       /* tp_repr */
00105 
00106     /* Method suites for standard classes */
00107 
00108     NULL,                       /* PyNumberMethods *tp_as_number; */
00109     NULL,                       /* PySequenceMethods *tp_as_sequence; */
00110     NULL,                       /* PyMappingMethods *tp_as_mapping; */
00111 
00112     /* More standard operations (here for binary compatibility) */
00113 
00114     NULL,                       /* hashfunc tp_hash; */
00115     NULL,                       /* ternaryfunc tp_call; */
00116     NULL,                       /* reprfunc tp_str; */
00117 
00118     /* will only use these if this is a subtype of a py class */
00119     NULL /*PyObject_GenericGetAttr is assigned later */,    /* getattrofunc tp_getattro; */
00120     NULL,                       /* setattrofunc tp_setattro; */
00121 
00122     /* Functions to access object as input/output buffer */
00123     NULL,                       /* PyBufferProcs *tp_as_buffer; */
00124 
00125   /*** Flags to define presence of optional/expanded features ***/
00126     Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
00127 
00128     NULL,                       /*  char *tp_doc;  Documentation string */
00129   /*** Assigned meaning in release 2.0 ***/
00130     /* call function for all accessible objects */
00131     NULL,                       /* traverseproc tp_traverse; */
00132 
00133     /* delete references to contained objects */
00134     NULL,                       /* inquiry tp_clear; */
00135 
00136   /***  Assigned meaning in release 2.1 ***/
00137   /*** rich comparisons ***/
00138     NULL, /* subclassed */      /* richcmpfunc tp_richcompare; */
00139 
00140   /***  weak reference enabler ***/
00141     0,
00142   /*** Added in release 2.2 ***/
00143     /*   Iterators */
00144     NULL,                       /* getiterfunc tp_iter; */
00145     NULL,                       /* iternextfunc tp_iternext; */
00146 
00147   /*** Attribute descriptor and subclassing stuff ***/
00148     bpy_lib_methods,            /* struct PyMethodDef *tp_methods; */
00149     NULL,                       /* struct PyMemberDef *tp_members; */
00150     NULL,                       /* struct PyGetSetDef *tp_getset; */
00151     NULL,                       /* struct _typeobject *tp_base; */
00152     NULL,                       /* PyObject *tp_dict; */
00153     NULL,                       /* descrgetfunc tp_descr_get; */
00154     NULL,                       /* descrsetfunc tp_descr_set; */
00155     offsetof(BPy_Library, dict),/* long tp_dictoffset; */
00156     NULL,                       /* initproc tp_init; */
00157     NULL,                       /* allocfunc tp_alloc; */
00158     NULL,                       /* newfunc tp_new; */
00159     /*  Low-level free-memory routine */
00160     NULL,                       /* freefunc tp_free;  */
00161     /* For PyObject_IS_GC */
00162     NULL,                       /* inquiry tp_is_gc;  */
00163     NULL,                       /* PyObject *tp_bases; */
00164     /* method resolution order */
00165     NULL,                       /* PyObject *tp_mro;  */
00166     NULL,                       /* PyObject *tp_cache; */
00167     NULL,                       /* PyObject *tp_subclasses; */
00168     NULL,                       /* PyObject *tp_weaklist; */
00169     NULL
00170 };
00171 
00172 PyDoc_STRVAR(bpy_lib_load_doc,
00173 ".. method:: load(filepath, link=False, relative=False)\n"
00174 "\n"
00175 "   Returns a context manager which exposes 2 library objects on entering.\n"
00176 "   Each object has attributes matching bpy.data which are lists of strings to be linked.\n"
00177 "\n"
00178 "   :arg filepath: The path to a blend file.\n"
00179 "   :type filepath: string\n"
00180 "   :arg link: When False reference to the original file is lost.\n"
00181 "   :type link: bool\n"
00182 "   :arg relative: When True the path is stored relative to the open blend file.\n"
00183 "   :type relative: bool\n"
00184 );
00185 static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
00186 {
00187     static const char *kwlist[] = {"filepath", "link", "relative", NULL};
00188     BPy_Library *ret;
00189     const char* filename = NULL;
00190     int is_rel = 0, is_link = 0;
00191 
00192     if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|ii:load", (char **)kwlist, &filename, &is_link, &is_rel))
00193         return NULL;
00194 
00195     ret = PyObject_New(BPy_Library, &bpy_lib_Type);
00196 
00197     BLI_strncpy(ret->relpath, filename, sizeof(ret->relpath));
00198     BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath));
00199     BLI_path_abs(ret->abspath, G.main->name);
00200 
00201     ret->blo_handle = NULL;
00202     ret->flag=  (is_link ? FILE_LINK : 0) |
00203                 (is_rel ? FILE_RELPATH : 0);
00204 
00205     ret->dict = PyDict_New();
00206 
00207     return (PyObject *)ret;
00208 }
00209 
00210 static PyObject *_bpy_names(BPy_Library *self, int blocktype)
00211 {
00212     PyObject *list;
00213     LinkNode *l, *names;
00214     int totnames;
00215 
00216     names = BLO_blendhandle_get_datablock_names(self->blo_handle, blocktype, &totnames);
00217 
00218     if (names) {
00219         int counter = 0;
00220         list = PyList_New(totnames);
00221         for (l = names; l; l = l->next) {
00222             PyList_SET_ITEM(list, counter, PyUnicode_FromString((char *)l->link));
00223             counter++;
00224         }
00225         BLI_linklist_free(names, free); /* free linklist *and* each node's data */
00226     }
00227     else {
00228         list = PyList_New(0);
00229     }
00230 
00231     return list;
00232 }
00233 
00234 static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args))
00235 {
00236     PyObject *ret;
00237     BPy_Library *self_from;
00238     PyObject *from_dict = PyDict_New();
00239     ReportList reports;
00240 
00241     BKE_reports_init(&reports, RPT_STORE);
00242 
00243     self->blo_handle = BLO_blendhandle_from_file(self->abspath, &reports);
00244 
00245     if (self->blo_handle == NULL) {
00246         if (BPy_reports_to_error(&reports, PyExc_IOError, TRUE) != -1) {
00247             PyErr_Format(PyExc_IOError,
00248                          "load: %s failed to open blend file",
00249                          self->abspath);
00250         }
00251         return NULL;
00252     }
00253     else {
00254         int i = 0, code;
00255         while ((code = BKE_idcode_iter_step(&i))) {
00256             if (BKE_idcode_is_linkable(code)) {
00257                 const char *name_plural = BKE_idcode_to_name_plural(code);
00258                 PyObject *str = PyUnicode_FromString(name_plural);
00259                 PyDict_SetItem(self->dict, str, PyList_New(0));
00260                 PyDict_SetItem(from_dict, str, _bpy_names(self, code));
00261                 Py_DECREF(str);
00262             }
00263         }
00264     }
00265 
00266     /* create a dummy */
00267     self_from = PyObject_New(BPy_Library, &bpy_lib_Type);
00268     BLI_strncpy(self_from->relpath, self->relpath, sizeof(self_from->relpath));
00269     BLI_strncpy(self_from->abspath, self->abspath, sizeof(self_from->abspath));
00270 
00271     self_from->blo_handle = NULL;
00272     self_from->flag = 0;
00273     self_from->dict = from_dict; /* owns the dict */
00274 
00275     /* return pair */
00276     ret = PyTuple_New(2);
00277 
00278     PyTuple_SET_ITEM(ret, 0, (PyObject *)self_from);
00279 
00280     PyTuple_SET_ITEM(ret, 1, (PyObject *)self);
00281     Py_INCREF(self);
00282 
00283     BKE_reports_clear(&reports);
00284 
00285     return ret;
00286 }
00287 
00288 static void bpy_lib_exit_warn_idname(BPy_Library *self, const char *name_plural, const char *idname)
00289 {
00290     PyObject *exc, *val, *tb;
00291     PyErr_Fetch(&exc, &val, &tb);
00292     if (PyErr_WarnFormat(PyExc_UserWarning, 1,
00293                          "load: '%s' does not contain %s[\"%s\"]",
00294                          self->abspath, name_plural, idname)) {
00295         /* Spurious errors can appear at shutdown */
00296         if (PyErr_ExceptionMatches(PyExc_Warning)) {
00297             PyErr_WriteUnraisable((PyObject *)self);
00298         }
00299     }
00300     PyErr_Restore(exc, val, tb);
00301 }
00302 
00303 static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item)
00304 {
00305     PyObject *exc, *val, *tb;
00306     PyErr_Fetch(&exc, &val, &tb);
00307     if (PyErr_WarnFormat(PyExc_UserWarning, 1,
00308                          "load: '%s' expected a string type, not a %.200s",
00309                          self->abspath, Py_TYPE(item)->tp_name)) {
00310         /* Spurious errors can appear at shutdown */
00311         if (PyErr_ExceptionMatches(PyExc_Warning)) {
00312             PyErr_WriteUnraisable((PyObject *)self);
00313         }
00314     }
00315     PyErr_Restore(exc, val, tb);
00316 }
00317 
00318 static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
00319 {
00320     Main *bmain = CTX_data_main(BPy_GetContext());
00321     Main *mainl = NULL;
00322     int err = 0;
00323 
00324     flag_all_listbases_ids(LIB_PRE_EXISTING, 1);
00325 
00326     /* here appending/linking starts */
00327     mainl = BLO_library_append_begin(bmain, &(self->blo_handle), self->relpath);
00328 
00329     {
00330         int i = 0, code;
00331         while ((code = BKE_idcode_iter_step(&i))) {
00332             if (BKE_idcode_is_linkable(code)) {
00333                 const char *name_plural = BKE_idcode_to_name_plural(code);
00334                 PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
00335                 // printf("lib: %s\n", name_plural);
00336                 if (ls && PyList_Check(ls)) {
00337                     /* loop */
00338                     Py_ssize_t size = PyList_GET_SIZE(ls);
00339                     Py_ssize_t i;
00340                     PyObject *item;
00341                     const char *item_str;
00342 
00343                     for (i = 0; i < size; i++) {
00344                         item = PyList_GET_ITEM(ls, i);
00345                         item_str = _PyUnicode_AsString(item);
00346 
00347                         // printf("  %s\n", item_str);
00348 
00349                         if (item_str) {
00350                             ID *id = BLO_library_append_named_part(mainl, &(self->blo_handle), item_str, code);
00351                             if (id) {
00352 #ifdef USE_RNA_DATABLOCKS
00353                                 PointerRNA id_ptr;
00354                                 RNA_id_pointer_create(id, &id_ptr);
00355                                 Py_DECREF(item);
00356                                 item = pyrna_struct_CreatePyObject(&id_ptr);
00357 #endif
00358                             }
00359                             else {
00360                                 bpy_lib_exit_warn_idname(self, name_plural, item_str);
00361                                 /* just warn for now */
00362                                 /* err = -1; */
00363 #ifdef USE_RNA_DATABLOCKS
00364                                 item = Py_None;
00365                                 Py_INCREF(item);
00366 #endif
00367                             }
00368 
00369                             /* ID or None */
00370                         }
00371                         else {
00372                             /* XXX, could complain about this */
00373                             bpy_lib_exit_warn_type(self, item);
00374                             PyErr_Clear();
00375 
00376 #ifdef USE_RNA_DATABLOCKS
00377                             item = Py_None;
00378                             Py_INCREF(item);
00379 #endif
00380                         }
00381 
00382 #ifdef USE_RNA_DATABLOCKS
00383                         PyList_SET_ITEM(ls, i, item);
00384 #endif
00385                     }
00386                 }
00387             }
00388         }
00389     }
00390 
00391     if (err == -1) {
00392         /* exception raised above, XXX, this leaks some memory */
00393         BLO_blendhandle_close(self->blo_handle);
00394         self->blo_handle = NULL;
00395         flag_all_listbases_ids(LIB_PRE_EXISTING, 0);
00396         return NULL;
00397     }
00398     else {
00399         Library *lib = mainl->curlib; /* newly added lib, assign before append end */
00400         BLO_library_append_end(NULL, mainl, &(self->blo_handle), 0, self->flag);
00401         BLO_blendhandle_close(self->blo_handle);
00402         self->blo_handle = NULL;
00403 
00404         {   /* copied from wm_operator.c */
00405             /* mark all library linked objects to be updated */
00406             recalc_all_library_objects(G.main);
00407 
00408             /* append, rather than linking */
00409             if ((self->flag & FILE_LINK) == 0) {
00410                 BKE_library_make_local(bmain, lib, 1);
00411             }
00412         }
00413 
00414         flag_all_listbases_ids(LIB_PRE_EXISTING, 0);
00415 
00416         Py_RETURN_NONE;
00417     }
00418 }
00419 
00420 static PyObject *bpy_lib_dir(BPy_Library *self)
00421 {
00422     return PyDict_Keys(self->dict);
00423 }
00424 
00425 
00426 int bpy_lib_init(PyObject *mod_par)
00427 {
00428     static PyMethodDef load_meth = {"load", (PyCFunction)bpy_lib_load,
00429                                    METH_STATIC|METH_VARARGS|METH_KEYWORDS,
00430                                    bpy_lib_load_doc};
00431 
00432     PyModule_AddObject(mod_par, "_library_load", PyCFunction_New(&load_meth, NULL));
00433 
00434     /* some compilers dont like accessing this directly, delay assignment */
00435     bpy_lib_Type.tp_getattro = PyObject_GenericGetAttr;
00436 
00437     if (PyType_Ready(&bpy_lib_Type) < 0)
00438         return -1;
00439 
00440     return 0;
00441 }