1 /*
2 *
3 * Copyright (C) 2006 MeVis Research GmbH All Rights Reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library 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 GNU
13 * Lesser General Public License for more details.
14 *
15 * Further, this software is distributed without any warranty that it is
16 * free of the rightful claim of any third person regarding infringement
17 * or the like. Any license provided herein, whether implied or
18 * otherwise, applies only to this software file. Patent licenses, if
19 * any, provided herein do not apply to combinations of this program with
20 * other software, or any other product whatsoever.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 * Contact information: MeVis Research GmbH, Universitaetsallee 29,
27 * 28359 Bremen, Germany or:
28 *
29 * http://www.mevis.de
30 *
31 */
32
33 //----------------------------------------------------------------------------------
34 /*!
35 // \file PythonQtImporter.h
36 // \author Florian Link
37 // \author Last changed by $Author: florian $
38 // \date 2006-05
39 */
40 // This module was inspired by the zipimport.c module of the original
41 // Python distribution. Most of the functions are identical or slightly
42 // modified to do all the loading of Python files via an external file interface.
43 // In contrast to zipimport.c, this module also writes *.pyc files
44 // automatically if it has write access/is not inside of a zip file.
45 //----------------------------------------------------------------------------------
46
47 #include "PythonQtImporter.h"
48 #include "PythonQtImportFileInterface.h"
49 #include "PythonQt.h"
50 #include <QFile>
51 #include <QFileInfo>
52
53 #define IS_SOURCE 0x0
54 #define IS_BYTECODE 0x1
55 #define IS_PACKAGE 0x2
56
57 struct st_mlab_searchorder {
58 char suffix[14];
59 int type;
60 };
61
62 /* mlab_searchorder defines how we search for a module in the Zip
63 archive: we first search for a package __init__, then for
64 non-package .pyc, .pyo and .py entries. The .pyc and .pyo entries
65 are swapped by initmlabimport() if we run in optimized mode. Also,
66 '/' is replaced by SEP there. */
67 struct st_mlab_searchorder mlab_searchorder[] = {
68 {"/__init__.pyc", IS_PACKAGE | IS_BYTECODE},
69 {"/__init__.pyo", IS_PACKAGE | IS_BYTECODE},
70 {"/__init__.py", IS_PACKAGE | IS_SOURCE},
71 {".pyc", IS_BYTECODE},
72 {".pyo", IS_BYTECODE},
73 {".py", IS_SOURCE},
74 {"", 0}
75 };
76
77 extern PyTypeObject PythonQtImporter_Type;
78 PyObject *PythonQtImportError;
79
getSubName(const QString & str)80 QString PythonQtImport::getSubName(const QString& str)
81 {
82 int idx = str.lastIndexOf('.');
83 if (idx!=-1) {
84 return str.mid(idx+1);
85 } else {
86 return str;
87 }
88 }
89
getModuleInfo(PythonQtImporter * self,const QString & fullname)90 PythonQtImport::module_info PythonQtImport::getModuleInfo(PythonQtImporter* self, const QString& fullname)
91 {
92 QString subname;
93 struct st_mlab_searchorder *zso;
94
95 subname = getSubName(fullname);
96 QString path = *self->_path + "/" + subname;
97
98 QString test;
99 for (zso = mlab_searchorder; *zso->suffix; zso++) {
100 test = path + zso->suffix;
101 if (PythonQt::importInterface()->exists(test)) {
102 if (zso->type & IS_PACKAGE)
103 return MI_PACKAGE;
104 else
105 return MI_MODULE;
106 }
107 }
108 return MI_NOT_FOUND;
109 }
110
111
112 /* PythonQtImporter.__init__
113 Just store the path argument
114 */
PythonQtImporter_init(PythonQtImporter * self,PyObject * args,PyObject * kwds)115 int PythonQtImporter_init(PythonQtImporter *self, PyObject *args, PyObject *kwds)
116 {
117 self->_path = NULL;
118
119 const char* path;
120 if (!PyArg_ParseTuple(args, "s",
121 &path))
122 return -1;
123
124 if (PythonQt::importInterface()->exists(path)) {
125 //qDebug("path %s", path);
126 QString p(path);
127 const QStringList& ignorePaths = PythonQt::self()->getImporterIgnorePaths();
128 foreach(QString a, ignorePaths) {
129 if (a==p) {
130 PyErr_SetString(PythonQtImportError,
131 "path ignored");
132 return -1;
133 }
134 }
135
136 self->_path = new QString(p);
137
138 //mlabDebugConst("MLABPython", "PythonQtImporter init: " << *self->_path);
139
140 return 0;
141 } else {
142 PyErr_SetString(PythonQtImportError,
143 "path does not exist error");
144 return -1;
145 }
146 }
147
148 void
PythonQtImporter_dealloc(PythonQtImporter * self)149 PythonQtImporter_dealloc(PythonQtImporter *self)
150 {
151 // free the stored path
152 if (self->_path) delete self->_path;
153 // free ourself
154 self->ob_type->tp_free((PyObject *)self);
155 }
156
157
158 /* Check whether we can satisfy the import of the module named by
159 'fullname'. Return self if we can, None if we can't. */
160 PyObject *
PythonQtImporter_find_module(PyObject * obj,PyObject * args)161 PythonQtImporter_find_module(PyObject *obj, PyObject *args)
162 {
163 PythonQtImporter *self = (PythonQtImporter *)obj;
164 PyObject *path = NULL;
165 char *fullname;
166
167 if (!PyArg_ParseTuple(args, "s|O:PythonQtImporter.find_module",
168 &fullname, &path))
169 return NULL;
170
171 // mlabDebugConst("MLABPython", "FindModule " << fullname << " in " << *self->_path);
172
173 PythonQtImport::module_info info = PythonQtImport::getModuleInfo(self, fullname);
174 if (info == PythonQtImport::MI_MODULE || info == PythonQtImport::MI_PACKAGE) {
175 Py_INCREF(self);
176 return (PyObject *)self;
177 } else {
178 Py_INCREF(Py_None);
179 return Py_None;
180 }
181 }
182
183 /* Load and return the module named by 'fullname'. */
184 PyObject *
PythonQtImporter_load_module(PyObject * obj,PyObject * args)185 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
186 {
187 PythonQtImporter *self = (PythonQtImporter *)obj;
188 PyObject *code, *mod, *dict;
189 char *fullname;
190 QString modpath;
191 int ispackage;
192
193 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.load_module",
194 &fullname))
195 return NULL;
196
197 code = PythonQtImport::getModuleCode(self, fullname, &ispackage, modpath);
198 if (code == NULL)
199 return NULL;
200
201 mod = PyImport_AddModule(fullname);
202 if (mod == NULL) {
203 Py_DECREF(code);
204 return NULL;
205 }
206 dict = PyModule_GetDict(mod);
207
208 if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0)
209 goto error;
210
211 if (ispackage) {
212 PyObject *pkgpath, *fullpath;
213 QString subname = PythonQtImport::getSubName(fullname);
214 int err;
215
216 fullpath = PyString_FromFormat("%s%c%s",
217 self->_path->toLatin1().constData(),
218 SEP,
219 subname.toLatin1().constData());
220 if (fullpath == NULL)
221 goto error;
222
223 pkgpath = Py_BuildValue("[O]", fullpath);
224 Py_DECREF(fullpath);
225 if (pkgpath == NULL)
226 goto error;
227 err = PyDict_SetItemString(dict, "__path__", pkgpath);
228 Py_DECREF(pkgpath);
229 if (err != 0)
230 goto error;
231 }
232 mod = PyImport_ExecCodeModuleEx(fullname, code, (char*)modpath.toLatin1().data());
233 Py_DECREF(code);
234 if (Py_VerboseFlag)
235 PySys_WriteStderr("import %s # loaded from %s\n",
236 fullname, (char*)modpath.toLatin1().data());
237 return mod;
238 error:
239 Py_DECREF(code);
240 Py_DECREF(mod);
241 return NULL;
242 }
243
244
245 PyObject *
PythonQtImporter_get_data(PyObject * obj,PyObject * args)246 PythonQtImporter_get_data(PyObject *obj, PyObject *args)
247 {
248 // EXTRA, NOT YET IMPLEMENTED
249 return NULL;
250 }
251
252 PyObject *
PythonQtImporter_get_code(PyObject * obj,PyObject * args)253 PythonQtImporter_get_code(PyObject *obj, PyObject *args)
254 {
255 PythonQtImporter *self = (PythonQtImporter *)obj;
256 char *fullname;
257
258 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.get_code", &fullname))
259 return NULL;
260
261 QString notused;
262 return PythonQtImport::getModuleCode(self, fullname, NULL, notused);
263 }
264
265 PyObject *
PythonQtImporter_get_source(PyObject * obj,PyObject * args)266 PythonQtImporter_get_source(PyObject *obj, PyObject *args)
267 {
268 // EXTRA, NOT YET IMPLEMENTED
269 /*
270 PythonQtImporter *self = (PythonQtImporter *)obj;
271 PyObject *toc_entry;
272 char *fullname, *subname, path[MAXPATHLEN+1];
273 int len;
274 enum module_info mi;
275
276 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.get_source", &fullname))
277 return NULL;
278
279 mi = get_module_info(self, fullname);
280 if (mi == MI_ERROR)
281 return NULL;
282 if (mi == MI_NOT_FOUND) {
283 PyErr_Format(PythonQtImportError, "can't find module '%.200s'",
284 fullname);
285 return NULL;
286 }
287 subname = get_subname(fullname);
288
289 len = make_filename(PyString_AsString(self->prefix), subname, path);
290 if (len < 0)
291 return NULL;
292
293 if (mi == MI_PACKAGE) {
294 path[len] = SEP;
295 strcpy(path + len + 1, "__init__.py");
296 }
297 else
298 strcpy(path + len, ".py");
299
300 toc_entry = PyDict_GetItemString(self->files, path);
301 if (toc_entry != NULL)
302 return get_data(PyString_AsString(self->archive), toc_entry);
303
304 Py_INCREF(Py_None);
305 return Py_None;
306 */
307 return NULL;
308 }
309
310 PyDoc_STRVAR(doc_find_module,
311 "find_module(fullname, path=None) -> self or None.\n\
312 \n\
313 Search for a module specified by 'fullname'. 'fullname' must be the\n\
314 fully qualified (dotted) module name. It returns the PythonQtImporter\n\
315 instance itself if the module was found, or None if it wasn't.\n\
316 The optional 'path' argument is ignored -- it's there for compatibility\n\
317 with the importer protocol.");
318
319 PyDoc_STRVAR(doc_load_module,
320 "load_module(fullname) -> module.\n\
321 \n\
322 Load the module specified by 'fullname'. 'fullname' must be the\n\
323 fully qualified (dotted) module name. It returns the imported\n\
324 module, or raises PythonQtImportError if it wasn't found.");
325
326 PyDoc_STRVAR(doc_get_data,
327 "get_data(pathname) -> string with file data.\n\
328 \n\
329 Return the data associated with 'pathname'. Raise IOError if\n\
330 the file wasn't found.");
331
332 PyDoc_STRVAR(doc_get_code,
333 "get_code(fullname) -> code object.\n\
334 \n\
335 Return the code object for the specified module. Raise PythonQtImportError\n\
336 is the module couldn't be found.");
337
338 PyDoc_STRVAR(doc_get_source,
339 "get_source(fullname) -> source string.\n\
340 \n\
341 Return the source code for the specified module. Raise PythonQtImportError\n\
342 is the module couldn't be found, return None if the archive does\n\
343 contain the module, but has no source for it.");
344
345 PyMethodDef PythonQtImporter_methods[] = {
346 {"find_module", PythonQtImporter_find_module, METH_VARARGS,
347 doc_find_module},
348 {"load_module", PythonQtImporter_load_module, METH_VARARGS,
349 doc_load_module},
350 {"get_data", PythonQtImporter_get_data, METH_VARARGS,
351 doc_get_data},
352 {"get_code", PythonQtImporter_get_code, METH_VARARGS,
353 doc_get_code},
354 {"get_source", PythonQtImporter_get_source, METH_VARARGS,
355 doc_get_source},
356 {NULL, NULL} /* sentinel */
357 };
358
359
360 PyDoc_STRVAR(PythonQtImporter_doc,
361 "PythonQtImporter(path) -> PythonQtImporter object\n\
362 \n\
363 Create a new PythonQtImporter instance. 'path' must be a valid path on disk/or inside of a zip file known to MeVisLab\n\
364 . Every path is accepted.");
365
366 #define DEFERRED_ADDRESS(ADDR) 0
367
368 PyTypeObject PythonQtImporter_Type = {
369 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
370 0,
371 "PythonQtImport.PythonQtImporter",
372 sizeof(PythonQtImporter),
373 0, /* tp_itemsize */
374 (destructor)PythonQtImporter_dealloc, /* tp_dealloc */
375 0, /* tp_print */
376 0, /* tp_getattr */
377 0, /* tp_setattr */
378 0, /* tp_compare */
379 0, /* tp_repr */
380 0, /* tp_as_number */
381 0, /* tp_as_sequence */
382 0, /* tp_as_mapping */
383 0, /* tp_hash */
384 0, /* tp_call */
385 0, /* tp_str */
386 PyObject_GenericGetAttr, /* tp_getattro */
387 0, /* tp_setattro */
388 0, /* tp_as_buffer */
389 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE , /* tp_flags */
390 PythonQtImporter_doc, /* tp_doc */
391 0, /* tp_traverse */
392 0, /* tp_clear */
393 0, /* tp_richcompare */
394 0, /* tp_weaklistoffset */
395 0, /* tp_iter */
396 0, /* tp_iternext */
397 PythonQtImporter_methods, /* tp_methods */
398 0, /* tp_members */
399 0, /* tp_getset */
400 0, /* tp_base */
401 0, /* tp_dict */
402 0, /* tp_descr_get */
403 0, /* tp_descr_set */
404 0, /* tp_dictoffset */
405 (initproc)PythonQtImporter_init, /* tp_init */
406 PyType_GenericAlloc, /* tp_alloc */
407 PyType_GenericNew, /* tp_new */
408 PyObject_Del, /* tp_free */
409 };
410
411
412 /* Given a buffer, return the long that is represented by the first
413 4 bytes, encoded as little endian. This partially reimplements
414 marshal.c:r_long() */
415 long
getLong(unsigned char * buf)416 PythonQtImport::getLong(unsigned char *buf)
417 {
418 long x;
419 x = buf[0];
420 x |= (long)buf[1] << 8;
421 x |= (long)buf[2] << 16;
422 x |= (long)buf[3] << 24;
423 #if SIZEOF_LONG > 4
424 /* Sign extension for 64-bit machines */
425 x |= -(x & 0x80000000L);
426 #endif
427 return x;
428 }
429
430 FILE *
open_exclusive(const QString & filename)431 open_exclusive(const QString& filename)
432 {
433 #if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC)
434 /* Use O_EXCL to avoid a race condition when another process tries to
435 write the same file. When that happens, our open() call fails,
436 which is just fine (since it's only a cache).
437 XXX If the file exists and is writable but the directory is not
438 writable, the file will never be written. Oh well.
439 */
440 QFile::remove(filename);
441
442 int fd;
443 int flags = O_EXCL|O_CREAT|O_WRONLY|O_TRUNC;
444 #ifdef O_BINARY
445 flags |= O_BINARY; /* necessary for Windows */
446 #endif
447 #ifdef WIN32
448 fd = _wopen(filename.ucs2(), flags, 0666);
449 #else
450 fd = open(filename.local8Bit(), flags, 0666);
451 #endif
452 if (fd < 0)
453 return NULL;
454 return fdopen(fd, "wb");
455 #else
456 /* Best we can do -- on Windows this can't happen anyway */
457 return fopen(filename.toLocal8Bit().constData(), "wb");
458 #endif
459 }
460
461
writeCompiledModule(PyCodeObject * co,const QString & filename,long mtime)462 void PythonQtImport::writeCompiledModule(PyCodeObject *co, const QString& filename, long mtime)
463 {
464 FILE *fp;
465
466 fp = open_exclusive(filename);
467 if (fp == NULL) {
468 if (Py_VerboseFlag)
469 PySys_WriteStderr(
470 "# can't create %s\n", filename.toLatin1().constData());
471 return;
472 }
473 #if PY_VERSION_HEX < 0x02040000
474 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp);
475 #else
476 PyMarshal_WriteLongToFile(PyImport_GetMagicNumber(), fp, Py_MARSHAL_VERSION);
477 #endif
478 /* First write a 0 for mtime */
479 #if PY_VERSION_HEX < 0x02040000
480 PyMarshal_WriteLongToFile(0L, fp);
481 #else
482 PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION);
483 #endif
484 #if PY_VERSION_HEX < 0x02040000
485 PyMarshal_WriteObjectToFile((PyObject *)co, fp);
486 #else
487 PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION);
488 #endif
489 if (ferror(fp)) {
490 if (Py_VerboseFlag)
491 PySys_WriteStderr("# can't write %s\n", filename.toLatin1().constData());
492 /* Don't keep partial file */
493 fclose(fp);
494 QFile::remove(filename);
495 return;
496 }
497 /* Now write the true mtime */
498 fseek(fp, 4L, 0);
499 #if PY_VERSION_HEX < 0x02040000
500 PyMarshal_WriteLongToFile(mtime, fp);
501 #else
502 PyMarshal_WriteLongToFile(mtime, fp, Py_MARSHAL_VERSION);
503 #endif
504 fflush(fp);
505 fclose(fp);
506 if (Py_VerboseFlag)
507 PySys_WriteStderr("# wrote %s\n", filename.toLatin1().constData());
508 //#ifdef macintosh
509 // PyMac_setfiletype(cpathname, 'Pyth', 'PYC ');
510 //#endif
511 }
512
513 /* Given the contents of a .py[co] file in a buffer, unmarshal the data
514 and return the code object. Return None if it the magic word doesn't
515 match (we do this instead of raising an exception as we fall back
516 to .py if available and we don't want to mask other errors).
517 Returns a new reference. */
518 PyObject *
unmarshalCode(const QString & path,const QByteArray & data,time_t mtime)519 PythonQtImport::unmarshalCode(const QString& path, const QByteArray& data, time_t mtime)
520 {
521 PyObject *code;
522 // ugly cast, but Python API is not const safe
523 char *buf = (char*) data.constData();
524 int size = data.size();
525
526 if (size <= 9) {
527 PySys_WriteStderr("# %s has bad pyc data\n",
528 path.toLatin1().constData());
529 Py_INCREF(Py_None);
530 return Py_None;
531 }
532
533 if (getLong((unsigned char *)buf) != PyImport_GetMagicNumber()) {
534 if (Py_VerboseFlag)
535 PySys_WriteStderr("# %s has bad magic\n",
536 path.toLatin1().constData());
537 Py_INCREF(Py_None);
538 return Py_None;
539 }
540
541 if (mtime != 0 && !(getLong((unsigned char *)buf + 4) == mtime)) {
542 if (Py_VerboseFlag)
543 PySys_WriteStderr("# %s has bad mtime\n",
544 path.toLatin1().constData());
545 Py_INCREF(Py_None);
546 return Py_None;
547 }
548
549 code = PyMarshal_ReadObjectFromString(buf + 8, size - 8);
550 if (code == NULL)
551 return NULL;
552 if (!PyCode_Check(code)) {
553 Py_DECREF(code);
554 PyErr_Format(PyExc_TypeError,
555 "compiled module %.200s is not a code object",
556 path.toLatin1().constData());
557 return NULL;
558 }
559 return code;
560 }
561
562
563 /* Given a string buffer containing Python source code, compile it
564 return and return a code object as a new reference. */
565 PyObject *
compileSource(const QString & path,const QByteArray & data)566 PythonQtImport::compileSource(const QString& path, const QByteArray& data)
567 {
568 PyObject *code;
569 QByteArray data1 = data;
570 // in qt4, data is null terminated
571 // data1.resize(data.size()+1);
572 // data1.data()[data.size()-1] = 0;
573 code = Py_CompileString(data.data(), path.toLatin1().constData(),
574 Py_file_input);
575 return code;
576 }
577
578
579 /* Return the code object for the module named by 'fullname' from the
580 Zip archive as a new reference. */
581 PyObject *
getCodeFromData(const QString & path,int isbytecode,int ispackage,time_t mtime)582 PythonQtImport::getCodeFromData(const QString& path, int isbytecode,int ispackage, time_t mtime)
583 {
584 bool hasImporter = PythonQt::importInterface()!=NULL;
585
586 PyObject *code;
587
588 QByteArray qdata;
589 if (!hasImporter) {
590 QFile file(path);
591 QIODevice::OpenMode flags = QIODevice::ReadOnly;
592 if (!isbytecode) {
593 flags |= QIODevice::Text;
594 }
595 if (!file.open(flags)) {
596 return NULL;
597 }
598 qdata = file.readAll();
599 } else {
600 if (!isbytecode) {
601 // mlabDebugConst("MLABPython", "reading source " << path);
602 bool ok;
603 qdata = PythonQt::importInterface()->readSourceFile(path, ok);
604 if (!ok) {
605 // mlabErrorConst("PythonQtImporter","File could not be verified" << path);
606 return NULL;
607 }
608 if (qdata == " ") {
609 qdata.clear();
610 }
611 } else {
612 qdata = PythonQt::importInterface()->readFileAsBytes(path);
613 }
614 }
615
616 if (isbytecode) {
617 // mlabDebugConst("MLABPython", "reading bytecode " << path);
618 code = unmarshalCode(path, qdata, mtime);
619 }
620 else {
621 // mlabDebugConst("MLABPython", "compiling source " << path);
622 code = compileSource(path, qdata);
623 // save a pyc file if possible
624 QDateTime time;
625 time = hasImporter?PythonQt::importInterface()->lastModifiedDate(path):QFileInfo(path).lastModified();
626 writeCompiledModule((PyCodeObject*)code, path+"c", time.toTime_t());
627 }
628 return code;
629 }
630
631 time_t
getMTimeOfSource(const QString & path)632 PythonQtImport::getMTimeOfSource(const QString& path)
633 {
634 time_t mtime = 0;
635 QString path2 = path;
636 path2.truncate(path.length()-1);
637 if (PythonQt::importInterface()->exists(path2)) {
638 mtime = PythonQt::importInterface()->lastModifiedDate(path2).toTime_t();
639 }
640 return mtime;
641 }
642
643 /* Get the code object associated with the module specified by
644 'fullname'. */
645 PyObject *
getModuleCode(PythonQtImporter * self,char * fullname,int * p_ispackage,QString & modpath)646 PythonQtImport::getModuleCode(PythonQtImporter *self, char *fullname,
647 int *p_ispackage, QString& modpath)
648 {
649 QString subname;
650 struct st_mlab_searchorder *zso;
651
652 subname = getSubName(fullname);
653 QString path = *self->_path + "/" + subname;
654
655 QString test;
656 for (zso = mlab_searchorder; *zso->suffix; zso++) {
657 PyObject *code = NULL;
658 test = path + zso->suffix;
659
660 if (Py_VerboseFlag > 1)
661 PySys_WriteStderr("# trying %s\n",
662 test.toLatin1().constData());
663 if (PythonQt::importInterface()->exists(test)) {
664 time_t mtime = 0;
665 int ispackage = zso->type & IS_PACKAGE;
666 int isbytecode = zso->type & IS_BYTECODE;
667
668 if (isbytecode)
669 mtime = getMTimeOfSource(test);
670 if (p_ispackage != NULL)
671 *p_ispackage = ispackage;
672 code = getCodeFromData(test, isbytecode, ispackage, mtime);
673 if (code == Py_None) {
674 Py_DECREF(code);
675 continue;
676 }
677 if (code != NULL)
678 modpath = test;
679 return code;
680 }
681 }
682 PyErr_Format(PythonQtImportError, "can't find module '%.200s'", fullname);
683
684 return NULL;
685 }
686
replaceExtension(const QString & str,const QString & ext)687 QString PythonQtImport::replaceExtension(const QString& str, const QString& ext)
688 {
689 QString r;
690 int i = str.lastIndexOf('.');
691 if (i!=-1) {
692 r = str.mid(0,i) + "." + ext;
693 } else {
694 r = str + "." + ext;
695 }
696 return r;
697 }
698
getCodeFromPyc(const QString & file)699 PyObject* PythonQtImport::getCodeFromPyc(const QString& file)
700 {
701 bool hasImporter = PythonQt::importInterface()!=NULL;
702
703 PyObject* code;
704 const static QString pycStr("pyc");
705 QString pyc = replaceExtension(file, pycStr);
706 if ((hasImporter && PythonQt::importInterface()->exists(pyc)) ||
707 (!hasImporter && QFile::exists(pyc))) {
708 time_t mtime = 0;
709 mtime = getMTimeOfSource(pyc);
710 code = getCodeFromData(pyc, true, false, mtime);
711 if (code != Py_None && code != NULL) {
712 return code;
713 }
714 if (code) {
715 Py_DECREF(code);
716 }
717 }
718 code = getCodeFromData(file,false,false,0);
719 return code;
720 }
721
722 /* Module init */
723
724 PyDoc_STRVAR(mlabimport_doc,
725 "Imports python files into MeVisLab, completely replaces internal python import");
726
init()727 void PythonQtImport::init()
728 {
729 PyObject *mod;
730
731 if (PyType_Ready(&PythonQtImporter_Type) < 0)
732 return;
733
734 /* Correct directory separator */
735 mlab_searchorder[0].suffix[0] = SEP;
736 mlab_searchorder[1].suffix[0] = SEP;
737 mlab_searchorder[2].suffix[0] = SEP;
738 if (Py_OptimizeFlag) {
739 /* Reverse *.pyc and *.pyo */
740 struct st_mlab_searchorder tmp;
741 tmp = mlab_searchorder[0];
742 mlab_searchorder[0] = mlab_searchorder[1];
743 mlab_searchorder[1] = tmp;
744 tmp = mlab_searchorder[3];
745 mlab_searchorder[3] = mlab_searchorder[4];
746 mlab_searchorder[4] = tmp;
747 }
748
749 mod = Py_InitModule4("PythonQtImport", NULL, mlabimport_doc,
750 NULL, PYTHON_API_VERSION);
751
752 PythonQtImportError = PyErr_NewException("PythonQtImport.PythonQtImportError",
753 PyExc_ImportError, NULL);
754 if (PythonQtImportError == NULL)
755 return;
756
757 Py_INCREF(PythonQtImportError);
758 if (PyModule_AddObject(mod, "PythonQtImportError",
759 PythonQtImportError) < 0)
760 return;
761
762 Py_INCREF(&PythonQtImporter_Type);
763 if (PyModule_AddObject(mod, "PythonQtImporter",
764 (PyObject *)&PythonQtImporter_Type) < 0)
765 return;
766
767 // set our importer into the path_hooks to handle all path on sys.path
768 PyObject* classobj = PyDict_GetItemString(PyModule_GetDict(mod), "PythonQtImporter");
769 PyObject* path_hooks = PySys_GetObject("path_hooks");
770 PyList_Append(path_hooks, classobj);
771 }
772