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