ok, apparently didn't commit this either. apparently includes a merge with trunk...
[blender-staging.git] / source / blender / python / generic / bpy_internal_import.c
1 /* 
2  * $Id: bpy_internal_import.c 21094 2009-06-23 00:09:26Z gsrb3d $
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * This is a new part of Blender.
23  *
24  * Contributor(s): Willian P. Germano
25  *
26  * ***** END GPL LICENSE BLOCK *****
27 */
28
29 #include "bpy_internal_import.h"
30 #include "DNA_text_types.h"
31 #include "DNA_ID.h"
32
33 #include "MEM_guardedalloc.h"
34 #include "BKE_text.h" /* txt_to_buf */  
35 #include "BKE_main.h"
36
37 static Main *bpy_import_main= NULL;
38
39 static void free_compiled_text(Text *text)
40 {
41         if(text->compiled) {
42                 Py_DECREF(( PyObject * )text->compiled);
43         }
44         text->compiled= NULL;
45 }
46
47 struct Main *bpy_import_main_get(void)
48 {
49         return bpy_import_main;
50 }
51
52 void bpy_import_main_set(struct Main *maggie)
53 {
54         bpy_import_main= maggie;
55 }
56
57 PyObject *bpy_text_import( Text *text )
58 {
59         char *buf = NULL;
60         char modulename[24];
61         int len;
62
63         if( !text->compiled ) {
64                 buf = txt_to_buf( text );
65                 text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input );
66                 MEM_freeN( buf );
67
68                 if( PyErr_Occurred(  ) ) {
69                         PyErr_Print(  );
70                         PyErr_Clear(  );
71                         PySys_SetObject("last_traceback", NULL);
72                         free_compiled_text( text );
73                         return NULL;
74                 }
75         }
76
77         len= strlen(text->id.name+2) - 3;
78         strncpy(modulename, text->id.name+2, len);
79         return PyImport_ExecCodeModule(modulename, text->compiled);
80 }
81
82 PyObject *bpy_text_import_name( char *name, int *found )
83 {
84         Text *text;
85         char txtname[22]; /* 21+NULL */
86         int namelen = strlen( name );
87 //XXX   Main *maggie= bpy_import_main ? bpy_import_main:G.main;
88         Main *maggie= bpy_import_main;
89         
90         *found= 0;
91
92         if(!maggie) {
93                 printf("ERROR: bpy_import_main_set() was not called before running python. this is a bug.\n");
94                 return NULL;
95         }
96         
97         if (namelen>21-3) return NULL; /* we know this cant be importable, the name is too long for blender! */
98         
99         memcpy( txtname, name, namelen );
100         memcpy( &txtname[namelen], ".py", 4 );
101
102         for(text = maggie->text.first; text; text = text->id.next) {
103                 if( !strcmp( txtname, text->id.name+2 ) )
104                         break;
105         }
106
107         if( !text )
108                 return NULL;
109         else
110                 *found = 1;
111         
112         return bpy_text_import(text);
113 }
114
115
116 /*
117  * find in-memory module and recompile
118  */
119
120 PyObject *bpy_text_reimport( PyObject *module, int *found )
121 {
122         Text *text;
123         const char *txtname;
124         const char *name;
125         char *buf = NULL;
126 //XXX   Main *maggie= bpy_import_main ? bpy_import_main:G.main;
127         Main *maggie= bpy_import_main;
128         
129         if(!maggie) {
130                 printf("ERROR: bpy_import_main_set() was not called before running python. this is a bug.\n");
131                 return NULL;
132         }
133         
134         *found= 0;
135         
136         /* get name, filename from the module itself */
137
138         txtname = PyModule_GetFilename( module );
139         name = PyModule_GetName( module );
140         if( !txtname || !name)
141                 return NULL;
142
143         /* look up the text object */
144         text = ( Text * ) & ( maggie->text.first );
145         while( text ) {
146                 if( !strcmp( txtname, text->id.name+2 ) )
147                         break;
148                 text = text->id.next;
149         }
150
151         /* uh-oh.... didn't find it */
152         if( !text )
153                 return NULL;
154         else
155                 *found = 1;
156
157         /* if previously compiled, free the object */
158         /* (can't see how could be NULL, but check just in case) */ 
159         if( text->compiled ){
160                 Py_DECREF( (PyObject *)text->compiled );
161         }
162
163         /* compile the buffer */
164         buf = txt_to_buf( text );
165         text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input );
166         MEM_freeN( buf );
167
168         /* if compile failed.... return this error */
169         if( PyErr_Occurred(  ) ) {
170                 PyErr_Print(  );
171                 PyErr_Clear(  );
172                 PySys_SetObject("last_traceback", NULL);
173                 free_compiled_text( text );
174                 return NULL;
175         }
176
177         /* make into a module */
178         return PyImport_ExecCodeModule( (char *)name, text->compiled );
179 }
180
181
182 static PyObject *blender_import( PyObject * self, PyObject * args,  PyObject * kw)
183 {
184         PyObject *exception, *err, *tb;
185         char *name;
186         int found= 0;
187         PyObject *globals = NULL, *locals = NULL, *fromlist = NULL;
188         PyObject *newmodule;
189         
190         //PyObject_Print(args, stderr, 0);
191         int dummy_val; /* what does this do?*/
192         static char *kwlist[] = {"name", "globals", "locals", "fromlist", "level", 0};
193         
194         if( !PyArg_ParseTupleAndKeywords( args, kw, "s|OOOi:bpy_import_meth", kwlist,
195                                &name, &globals, &locals, &fromlist, &dummy_val) )
196                 return NULL;
197
198         /* import existing builtin modules or modules that have been imported alredy */
199         newmodule = PyImport_ImportModuleEx( name, globals, locals, fromlist );
200         
201         if(newmodule)
202                 return newmodule;
203         
204         PyErr_Fetch( &exception, &err, &tb );   /* get the python error incase we cant import as blender text either */
205         
206         /* importing from existing modules failed, see if we have this module as blender text */
207         newmodule = bpy_text_import_name( name, &found );
208         
209         if( newmodule ) {/* found module as blender text, ignore above exception */
210                 PyErr_Clear(  );
211                 Py_XDECREF( exception );
212                 Py_XDECREF( err );
213                 Py_XDECREF( tb );
214                 /* printf( "imported from text buffer...\n" ); */
215         }
216         else if (found==1) { /* blender text module failed to execute but was found, use its error message */
217                 Py_XDECREF( exception );
218                 Py_XDECREF( err );
219                 Py_XDECREF( tb );
220                 return NULL;
221         }
222         else {
223                 /* no blender text was found that could import the module
224                  * rause the original error from PyImport_ImportModuleEx */
225                 PyErr_Restore( exception, err, tb );
226         }
227         return newmodule;
228 }
229
230
231 /*
232  * our reload() module, to handle reloading in-memory scripts
233  */
234
235 static PyObject *blender_reload( PyObject * self, PyObject * args )
236 {
237         PyObject *exception, *err, *tb;
238         PyObject *module = NULL;
239         PyObject *newmodule = NULL;
240         int found= 0;
241         
242         /* check for a module arg */
243         if( !PyArg_ParseTuple( args, "O:bpy_reload_meth", &module ) )
244                 return NULL;
245
246         /* try reimporting from file */
247         newmodule = PyImport_ReloadModule( module );
248         if( newmodule )
249                 return newmodule;
250
251         /* no file, try importing from memory */
252         PyErr_Fetch( &exception, &err, &tb );   /*restore for probable later use */
253
254         newmodule = bpy_text_reimport( module, &found );
255         if( newmodule ) {/* found module as blender text, ignore above exception */
256                 PyErr_Clear(  );
257                 Py_XDECREF( exception );
258                 Py_XDECREF( err );
259                 Py_XDECREF( tb );
260                 /* printf( "imported from text buffer...\n" ); */
261         }
262         else if (found==1) { /* blender text module failed to execute but was found, use its error message */
263                 Py_XDECREF( exception );
264                 Py_XDECREF( err );
265                 Py_XDECREF( tb );
266                 return NULL;
267         }
268         else {
269                 /* no blender text was found that could import the module
270                  * rause the original error from PyImport_ImportModuleEx */
271                 PyErr_Restore( exception, err, tb );
272         }
273
274         return newmodule;
275 }
276
277 PyMethodDef bpy_import_meth[] = { {"bpy_import_meth", (PyCFunction)blender_import, METH_VARARGS | METH_KEYWORDS, "blenders import"} };
278 PyMethodDef bpy_reload_meth[] = { {"bpy_reload_meth", (PyCFunction)blender_reload, METH_VARARGS, "blenders reload"} };
279
280
281 /* Clear user modules.
282  * This is to clear any modules that could be defined from running scripts in blender.
283  * 
284  * Its also needed for the BGE Python api so imported scripts are not used between levels
285  * 
286  * This clears every modules that has a __file__ attribute (is not a builtin)
287  *
288  * Note that clearing external python modules is important for the BGE otherwise
289  * it wont reload scripts between loading different blend files or while making the game.
290  * - use 'clear_all' arg in this case.
291  *
292  * Since pythons bultins include a full path even for win32.
293  * even if we remove a python module a reimport will bring it back again.
294  */
295
296 #if 0 // not used anymore but may still come in handy later
297
298 #if defined(WIN32) || defined(WIN64)
299 #define SEPSTR "\\"
300 #else
301 #define SEPSTR "/"
302 #endif
303
304
305 void bpy_text_clear_modules(int clear_all)
306 {
307         PyObject *modules= PySys_GetObject("modules");
308         
309         char *fname;
310         char *file_extension;
311         
312         /* looping over the dict */
313         PyObject *key, *value;
314         int pos = 0;
315         
316         /* new list */
317         PyObject *list;
318
319         if (modules==NULL)
320                 return; /* should never happen but just incase */
321
322         list= PyList_New(0);
323
324         /* go over sys.modules and remove anything with a 
325          * sys.modukes[x].__file__ thats ends with a .py and has no path
326          */
327         while (PyDict_Next(modules, &pos, &key, &value)) {
328                 fname= PyModule_GetFilename(value);
329                 if(fname) {
330                         if (clear_all || ((strstr(fname, SEPSTR))==0)) { /* no path ? */
331                                 file_extension = strstr(fname, ".py");
332                                 if(file_extension && (*(file_extension + 3) == '\0' || *(file_extension + 4) == '\0')) { /* .py or pyc extension? */
333                                         /* now we can be fairly sure its a python import from the blendfile */
334                                         PyList_Append(list, key); /* free'd with the list */
335                                 }
336                         }
337                 }
338                 else {
339                         PyErr_Clear();
340                 }
341         }
342         
343         /* remove all our modules */
344         for(pos=0; pos < PyList_Size(list); pos++) {
345                 /* PyObject_Print(key, stderr, 0); */
346                 key= PyList_GET_ITEM(list, pos);
347                 PyDict_DelItem(modules, key);
348         }
349         
350         Py_DECREF(list); /* removes all references from append */
351 }
352 #endif