Committing patch "[#27676] Change window size/resolution in realtime" by me.
[blender-staging.git] / source / blender / python / generic / bpy_internal_import.c
1 /* 
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * This is a new part of Blender.
19  *
20  * Contributor(s): Willian P. Germano, Campbell Barton
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/python/generic/bpy_internal_import.c
26  *  \ingroup pygen
27  *
28  * This file defines replacements for pythons '__import__' and 'imp.reload'
29  * functions which can import from blender textblocks.
30  *
31  * \note
32  * This should eventually be replaced by import hooks (pep 302).
33  */
34
35
36 #include <Python.h>
37 #include <stddef.h>
38
39 #include "bpy_internal_import.h"
40
41 #include "MEM_guardedalloc.h"
42
43 #include "DNA_text_types.h"
44
45 #include "BLI_listbase.h"
46 #include "BLI_path_util.h"
47 #include "BLI_string.h"
48 #include "BLI_utildefines.h"
49
50  /* UNUSED */   
51 #include "BKE_text.h" /* txt_to_buf */  
52 #include "BKE_main.h"
53
54 static Main *bpy_import_main = NULL;
55
56 /* 'builtins' is most likely PyEval_GetBuiltins() */
57 void bpy_import_init(PyObject *builtins)
58 {
59         PyObject *item;
60         PyObject *mod;
61
62         PyDict_SetItemString(builtins, "__import__", item = PyCFunction_New(&bpy_import_meth, NULL)); Py_DECREF(item);
63
64         /* move reload here
65          * XXX, use import hooks */
66         mod = PyImport_ImportModuleLevel((char *)"imp", NULL, NULL, NULL, 0);
67         if (mod) {
68                 PyDict_SetItemString(PyModule_GetDict(mod), "reload", item = PyCFunction_New(&bpy_reload_meth, NULL)); Py_DECREF(item);
69                 Py_DECREF(mod);
70         }
71         else {
72                 BLI_assert(!"unable to load 'imp' module.");
73         }
74 }
75
76
77 static void free_compiled_text(Text *text)
78 {
79         if (text->compiled) {
80                 Py_DECREF((PyObject *)text->compiled);
81         }
82         text->compiled = NULL;
83 }
84
85 struct Main *bpy_import_main_get(void)
86 {
87         return bpy_import_main;
88 }
89
90 void bpy_import_main_set(struct Main *maggie)
91 {
92         bpy_import_main = maggie;
93 }
94
95 /* returns a dummy filename for a textblock so we can tell what file a text block comes from */
96 void bpy_text_filename_get(char *fn, size_t fn_len, Text *text)
97 {
98         BLI_snprintf(fn, fn_len, "%s%c%s", ID_BLEND_PATH(bpy_import_main, &text->id), SEP, text->id.name + 2);
99 }
100
101 PyObject *bpy_text_import(Text *text)
102 {
103         char *buf = NULL;
104         char modulename[MAX_ID_NAME+2];
105         int len;
106
107         if (!text->compiled) {
108                 char fn_dummy[256];
109                 bpy_text_filename_get(fn_dummy, sizeof(fn_dummy), text);
110
111                 buf = txt_to_buf(text);
112                 text->compiled = Py_CompileString(buf, fn_dummy, Py_file_input);
113                 MEM_freeN(buf);
114
115                 if (PyErr_Occurred()) {
116                         PyErr_Print();
117                         PyErr_Clear();
118                         PySys_SetObject("last_traceback", NULL);
119                         free_compiled_text(text);
120                         return NULL;
121                 }
122         }
123
124         len = strlen(text->id.name + 2);
125         BLI_strncpy(modulename, text->id.name + 2, len);
126         modulename[len - 3] = '\0'; /* remove .py */
127         return PyImport_ExecCodeModule(modulename, text->compiled);
128 }
129
130 PyObject *bpy_text_import_name(const char *name, int *found)
131 {
132         Text *text;
133         char txtname[MAX_ID_NAME - 2];
134         int namelen = strlen(name);
135 //XXX   Main *maggie = bpy_import_main ? bpy_import_main:G.main;
136         Main *maggie = bpy_import_main;
137         
138         *found = 0;
139
140         if (!maggie) {
141                 printf("ERROR: bpy_import_main_set() was not called before running python. this is a bug.\n");
142                 return NULL;
143         }
144
145         /* we know this cant be importable, the name is too long for blender! */
146         if (namelen >= (MAX_ID_NAME - 2) - 3) return NULL;
147
148         memcpy(txtname, name, namelen);
149         memcpy(&txtname[namelen], ".py", 4);
150
151         text = BLI_findstring(&maggie->text, txtname, offsetof(ID, name) + 2);
152
153         if (!text)
154                 return NULL;
155         else
156                 *found = 1;
157         
158         return bpy_text_import(text);
159 }
160
161
162 /*
163  * find in-memory module and recompile
164  */
165
166 PyObject *bpy_text_reimport(PyObject *module, int *found)
167 {
168         Text *text;
169         const char *name;
170         char *filepath;
171         char *buf = NULL;
172 //XXX   Main *maggie = bpy_import_main ? bpy_import_main:G.main;
173         Main *maggie = bpy_import_main;
174         
175         if (!maggie) {
176                 printf("ERROR: bpy_import_main_set() was not called before running python. this is a bug.\n");
177                 return NULL;
178         }
179         
180         *found = 0;
181         
182         /* get name, filename from the module itself */
183         if ((name = PyModule_GetName(module)) == NULL)
184                 return NULL;
185
186         if ((filepath = (char *)PyModule_GetFilename(module)) == NULL)
187                 return NULL;
188
189         /* look up the text object */
190         text = BLI_findstring(&maggie->text, BLI_path_basename(filepath), offsetof(ID, name) + 2);
191
192         /* uh-oh.... didn't find it */
193         if (!text)
194                 return NULL;
195         else
196                 *found = 1;
197
198         /* if previously compiled, free the object */
199         /* (can't see how could be NULL, but check just in case) */ 
200         if (text->compiled) {
201                 Py_DECREF((PyObject *)text->compiled);
202         }
203
204         /* compile the buffer */
205         buf = txt_to_buf(text);
206         text->compiled = Py_CompileString(buf, text->id.name + 2, Py_file_input);
207         MEM_freeN(buf);
208
209         /* if compile failed.... return this error */
210         if (PyErr_Occurred()) {
211                 PyErr_Print();
212                 PyErr_Clear();
213                 PySys_SetObject("last_traceback", NULL);
214                 free_compiled_text(text);
215                 return NULL;
216         }
217
218         /* make into a module */
219         return PyImport_ExecCodeModule((char *)name, text->compiled);
220 }
221
222
223 static PyObject *blender_import(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
224 {
225         PyObject *exception, *err, *tb;
226         char *name;
227         int found = 0;
228         PyObject *globals = NULL, *locals = NULL, *fromlist = NULL;
229         int level = -1; /* relative imports */
230         
231         PyObject *newmodule;
232         //PyObject_Print(args, stderr, 0);
233         static const char *kwlist[] = {"name", "globals", "locals", "fromlist", "level", NULL};
234         
235         if (!PyArg_ParseTupleAndKeywords(args, kw, "s|OOOi:bpy_import_meth", (char **)kwlist,
236                                          &name, &globals, &locals, &fromlist, &level))
237         {
238                 return NULL;
239         }
240
241         /* import existing builtin modules or modules that have been imported already */
242         newmodule = PyImport_ImportModuleLevel(name, globals, locals, fromlist, level);
243         
244         if (newmodule)
245                 return newmodule;
246         
247         PyErr_Fetch(&exception, &err, &tb);     /* get the python error incase we cant import as blender text either */
248         
249         /* importing from existing modules failed, see if we have this module as blender text */
250         newmodule = bpy_text_import_name(name, &found);
251         
252         if (newmodule) {/* found module as blender text, ignore above exception */
253                 PyErr_Clear();
254                 Py_XDECREF(exception);
255                 Py_XDECREF(err);
256                 Py_XDECREF(tb);
257                 /* printf("imported from text buffer...\n"); */
258         }
259         else if (found == 1) { /* blender text module failed to execute but was found, use its error message */
260                 Py_XDECREF(exception);
261                 Py_XDECREF(err);
262                 Py_XDECREF(tb);
263                 return NULL;
264         }
265         else {
266                 /* no blender text was found that could import the module
267                  * rause the original error from PyImport_ImportModuleEx */
268                 PyErr_Restore(exception, err, tb);
269         }
270         return newmodule;
271 }
272
273
274 /*
275  * our reload() module, to handle reloading in-memory scripts
276  */
277
278 static PyObject *blender_reload(PyObject *UNUSED(self), PyObject *module)
279 {
280         PyObject *exception, *err, *tb;
281         PyObject *newmodule = NULL;
282         int found = 0;
283
284         /* try reimporting from file */
285         newmodule = PyImport_ReloadModule(module);
286         if (newmodule)
287                 return newmodule;
288
289         /* no file, try importing from memory */
290         PyErr_Fetch(&exception, &err, &tb);     /*restore for probable later use */
291
292         newmodule = bpy_text_reimport(module, &found);
293         if (newmodule) {/* found module as blender text, ignore above exception */
294                 PyErr_Clear();
295                 Py_XDECREF(exception);
296                 Py_XDECREF(err);
297                 Py_XDECREF(tb);
298                 /* printf("imported from text buffer...\n"); */
299         }
300         else if (found == 1) { /* blender text module failed to execute but was found, use its error message */
301                 Py_XDECREF(exception);
302                 Py_XDECREF(err);
303                 Py_XDECREF(tb);
304                 return NULL;
305         }
306         else {
307                 /* no blender text was found that could import the module
308                  * reuse the original error from PyImport_ImportModuleEx */
309                 PyErr_Restore(exception, err, tb);
310         }
311
312         return newmodule;
313 }
314
315 PyMethodDef bpy_import_meth = {"bpy_import_meth", (PyCFunction)blender_import, METH_VARARGS | METH_KEYWORDS, "blenders import"};
316 PyMethodDef bpy_reload_meth = {"bpy_reload_meth", (PyCFunction)blender_reload, METH_O, "blenders reload"};