##// END OF EJS Templates
added support for shared library loading in custom importer by using imp.find_module and imp.load_module...
florianlink -
r83:48da745fc84a
parent child
Show More
@@ -47,6 +47,7
47 47 #include "PythonQtImporter.h"
48 48 #include "PythonQtImportFileInterface.h"
49 49 #include "PythonQt.h"
50 #include "PythonQtConversion.h"
50 51 #include <QFile>
51 52 #include <QFileInfo>
52 53
@@ -87,8 +88,9 QString PythonQtImport::getSubName(const QString& str)
87 88 }
88 89 }
89 90
90 PythonQtImport::module_info PythonQtImport::getModuleInfo(PythonQtImporter* self, const QString& fullname)
91 PythonQtImport::ModuleInfo PythonQtImport::getModuleInfo(PythonQtImporter* self, const QString& fullname)
91 92 {
93 ModuleInfo info;
92 94 QString subname;
93 95 struct st_mlab_searchorder *zso;
94 96
@@ -99,16 +101,22 PythonQtImport::module_info PythonQtImport::getModuleInfo(PythonQtImporter* self
99 101 for (zso = mlab_searchorder; *zso->suffix; zso++) {
100 102 test = path + zso->suffix;
101 103 if (PythonQt::importInterface()->exists(test)) {
102 if (zso->type & IS_PACKAGE)
103 return MI_PACKAGE;
104 else
105 return MI_MODULE;
104 info.fullPath = test;
105 info.moduleName = subname;
106 info.type = (zso->type & IS_PACKAGE)?MI_PACKAGE:MI_MODULE;
107 return info;
106 108 }
107 109 }
108 if (PythonQt::importInterface()->exists(path+".so")) {
109 return MI_SHAREDLIBRARY;
110 // test if it is a shared library
111 foreach(const QString& suffix, PythonQt::priv()->sharedLibrarySuffixes()) {
112 test = path+suffix;
113 if (PythonQt::importInterface()->exists(test)) {
114 info.fullPath = test;
115 info.moduleName = subname;
116 info.type = MI_SHAREDLIBRARY;
117 }
110 118 }
111 return MI_NOT_FOUND;
119 return info;
112 120 }
113 121
114 122
@@ -167,13 +175,10 PythonQtImporter_find_module(PyObject *obj, PyObject *args)
167 175 &fullname, &path))
168 176 return NULL;
169 177
170 qDebug() << "looking for " << fullname << " at " << *self->_path;
178 //qDebug() << "looking for " << fullname << " at " << *self->_path;
171 179
172 // mlabDebugConst("MLABPython", "FindModule " << fullname << " in " << *self->_path);
173
174 PythonQtImport::module_info info = PythonQtImport::getModuleInfo(self, fullname);
175 if (info == PythonQtImport::MI_MODULE || info == PythonQtImport::MI_PACKAGE ||
176 info== PythonQtImport::MI_SHAREDLIBRARY) {
180 PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname);
181 if (info.type != PythonQtImport::MI_NOT_FOUND) {
177 182 Py_INCREF(self);
178 183 return (PyObject *)self;
179 184 } else {
@@ -187,68 +192,107 PyObject *
187 192 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
188 193 {
189 194 PythonQtImporter *self = (PythonQtImporter *)obj;
190 PyObject *code, *mod, *dict;
195 PyObject *code = NULL, *mod = NULL, *dict = NULL;
191 196 char *fullname;
192 QString modpath;
193 int ispackage;
194 197
195 198 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.load_module",
196 199 &fullname))
197 200 return NULL;
198 201
199 code = PythonQtImport::getModuleCode(self, fullname, &ispackage, modpath);
200 if (code == NULL) {
201 return NULL;
202 }
203
204 mod = PyImport_AddModule(fullname);
205 if (mod == NULL) {
206 Py_DECREF(code);
202 PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname);
203 if (info.type == PythonQtImport::MI_NOT_FOUND) {
207 204 return NULL;
208 205 }
209 dict = PyModule_GetDict(mod);
210 206
211 if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0) {
212 Py_DECREF(code);
213 Py_DECREF(mod);
214 return NULL;
215 }
216
217 if (ispackage) {
218 PyObject *pkgpath, *fullpath;
219 QString subname = PythonQtImport::getSubName(fullname);
220 int err;
221
222 fullpath = PyString_FromFormat("%s%c%s",
223 self->_path->toLatin1().constData(),
224 SEP,
225 subname.toLatin1().constData());
226 if (fullpath == NULL) {
227 Py_DECREF(code);
228 Py_DECREF(mod);
207 if (info.type == PythonQtImport::MI_PACKAGE || info.type == PythonQtImport::MI_MODULE) {
208 QString fullPath;
209 code = PythonQtImport::getModuleCode(self, fullname, fullPath);
210 if (code == NULL) {
229 211 return NULL;
230 212 }
231 213
232 pkgpath = Py_BuildValue("[O]", fullpath);
233 Py_DECREF(fullpath);
234 if (pkgpath == NULL) {
214 mod = PyImport_AddModule(fullname);
215 if (mod == NULL) {
235 216 Py_DECREF(code);
236 Py_DECREF(mod);
237 217 return NULL;
238 218 }
239 err = PyDict_SetItemString(dict, "__path__", pkgpath);
240 Py_DECREF(pkgpath);
241 if (err != 0) {
219 dict = PyModule_GetDict(mod);
220
221 if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0) {
242 222 Py_DECREF(code);
243 223 Py_DECREF(mod);
244 224 return NULL;
245 225 }
246 }
247 mod = PyImport_ExecCodeModuleEx(fullname, code, (char*)modpath.toLatin1().data());
248 Py_DECREF(code);
249 if (Py_VerboseFlag) {
250 PySys_WriteStderr("import %s # loaded from %s\n",
251 fullname, modpath.toLatin1().constData());
226
227 if (info.type == PythonQtImport::MI_PACKAGE) {
228 PyObject *pkgpath, *fullpath;
229 QString subname = info.moduleName;
230 int err;
231
232 fullpath = PyString_FromFormat("%s%c%s",
233 self->_path->toLatin1().constData(),
234 SEP,
235 subname.toLatin1().constData());
236 if (fullpath == NULL) {
237 Py_DECREF(code);
238 Py_DECREF(mod);
239 return NULL;
240 }
241
242 pkgpath = Py_BuildValue("[O]", fullpath);
243 Py_DECREF(fullpath);
244 if (pkgpath == NULL) {
245 Py_DECREF(code);
246 Py_DECREF(mod);
247 return NULL;
248 }
249 err = PyDict_SetItemString(dict, "__path__", pkgpath);
250 Py_DECREF(pkgpath);
251 if (err != 0) {
252 Py_DECREF(code);
253 Py_DECREF(mod);
254 return NULL;
255 }
256 }
257 mod = PyImport_ExecCodeModuleEx(fullname, code, fullPath.toLatin1().data());
258 Py_DECREF(code);
259 if (Py_VerboseFlag) {
260 PySys_WriteStderr("import %s # loaded from %s\n",
261 fullname, fullPath.toLatin1().constData());
262 }
263 } else {
264 PythonQtObjectPtr imp;
265 imp.setNewRef(PyImport_ImportModule("imp"));
266
267 // Create a PyList with the current path as its single element,
268 // which is required for find_module (it won't accept a tuple...)
269 PythonQtObjectPtr pathList;
270 pathList.setNewRef(PythonQtConv::QStringListToPyList(QStringList() << *self->_path));
271
272 QVariantList args;
273 // Pass the module name without the package prefix
274 args.append(info.moduleName);
275 // And the path where we know that the shared library is
276 args.append(QVariant::fromValue(pathList));
277 QVariant result = imp.call("find_module", args);
278 if (result.isValid()) {
279 // This will return a tuple with (file, pathname, description)
280 QVariantList list = result.toList();
281 if (list.count()==3) {
282 // We prepend the full module name (including package prefix)
283 list.prepend(fullname);
284 // And call "load_module" with (fullname, file, pathname, description)
285 PythonQtObjectPtr module = imp.call("load_module", list);
286 mod = module.object();
287 if (mod) {
288 Py_INCREF(mod);
289 }
290
291 // Finally, we need to close the file again, which find_module opened for us
292 PythonQtObjectPtr file = list.at(1);
293 file.call("close");
294 }
295 }
252 296 }
253 297 return mod;
254 298 }
@@ -271,51 +315,13 PythonQtImporter_get_code(PyObject *obj, PyObject *args)
271 315 return NULL;
272 316
273 317 QString notused;
274 return PythonQtImport::getModuleCode(self, fullname, NULL, notused);
318 return PythonQtImport::getModuleCode(self, fullname, notused);
275 319 }
276 320
277 321 PyObject *
278 322 PythonQtImporter_get_source(PyObject * /*obj*/, PyObject * /*args*/)
279 323 {
280 324 // EXTRA, NOT YET IMPLEMENTED
281 /*
282 PythonQtImporter *self = (PythonQtImporter *)obj;
283 PyObject *toc_entry;
284 char *fullname, *subname, path[MAXPATHLEN+1];
285 int len;
286 enum module_info mi;
287
288 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.get_source", &fullname))
289 return NULL;
290
291 mi = get_module_info(self, fullname);
292 if (mi == MI_ERROR)
293 return NULL;
294 if (mi == MI_NOT_FOUND) {
295 PyErr_Format(PythonQtImportError, "can't find module '%.200s'",
296 fullname);
297 return NULL;
298 }
299 subname = get_subname(fullname);
300
301 len = make_filename(PyString_AsString(self->prefix), subname, path);
302 if (len < 0)
303 return NULL;
304
305 if (mi == MI_PACKAGE) {
306 path[len] = SEP;
307 strcpy(path + len + 1, "__init__.py");
308 }
309 else
310 strcpy(path + len, ".py");
311
312 toc_entry = PyDict_GetItemString(self->files, path);
313 if (toc_entry != NULL)
314 return get_data(PyString_AsString(self->archive), toc_entry);
315
316 Py_INCREF(Py_None);
317 return Py_None;
318 */
319 325 return NULL;
320 326 }
321 327
@@ -648,8 +654,7 PythonQtImport::getMTimeOfSource(const QString& path)
648 654 /* Get the code object associated with the module specified by
649 655 'fullname'. */
650 656 PyObject *
651 PythonQtImport::getModuleCode(PythonQtImporter *self, char *fullname,
652 int *p_ispackage, QString& modpath)
657 PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QString& modpath)
653 658 {
654 659 QString subname;
655 660 struct st_mlab_searchorder *zso;
@@ -670,17 +675,17 PythonQtImport::getModuleCode(PythonQtImporter *self, char *fullname,
670 675 int ispackage = zso->type & IS_PACKAGE;
671 676 int isbytecode = zso->type & IS_BYTECODE;
672 677
673 if (isbytecode)
678 if (isbytecode) {
674 679 mtime = getMTimeOfSource(test);
675 if (p_ispackage != NULL)
676 *p_ispackage = ispackage;
680 }
677 681 code = getCodeFromData(test, isbytecode, ispackage, mtime);
678 682 if (code == Py_None) {
679 683 Py_DECREF(code);
680 684 continue;
681 685 }
682 if (code != NULL)
686 if (code != NULL) {
683 687 modpath = test;
688 }
684 689 return code;
685 690 }
686 691 }
@@ -66,12 +66,21 typedef struct _PythonQtImporter {
66 66 class PythonQtImport
67 67 {
68 68 public:
69 enum module_info {
70 MI_ERROR,
71 MI_NOT_FOUND,
72 MI_MODULE,
73 MI_PACKAGE,
74 MI_SHAREDLIBRARY
69
70 enum ModuleType {
71 MI_NOT_FOUND,
72 MI_MODULE,
73 MI_PACKAGE,
74 MI_SHAREDLIBRARY
75 };
76
77 struct ModuleInfo {
78 ModuleInfo() {
79 type = MI_NOT_FOUND;
80 }
81 QString fullPath; //!< the full path to the found file
82 QString moduleName; //!< the module name without the package prefix
83 ModuleType type;
75 84 };
76 85
77 86 //! initialize
@@ -98,15 +107,15 public:
98 107
99 108 //! Get the code object associated with the module specified by
100 109 //! 'fullname'.
101 static PyObject * getModuleCode(PythonQtImporter *self, char *fullname,
102 int *p_ispackage, QString& modpath);
110 static PyObject * getModuleCode(PythonQtImporter *self,
111 const char* fullname, QString& modpath);
103 112
104 113
105 114 //! gets the compiled code for the given *.py file if there is a valid pyc file, otherwise compiles the file and writes the pyc
106 115 static PyObject* getCodeFromPyc(const QString& file);
107 116
108 117 //! Return if module exists and is a package or a module
109 static module_info getModuleInfo(PythonQtImporter* self, const QString& fullname);
118 static ModuleInfo getModuleInfo(PythonQtImporter* self, const QString& fullname);
110 119
111 120 //! get the last name of a dot chain (first.second.last)
112 121 static QString getSubName(const QString& str);
General Comments 0
You need to be logged in to leave comments. Login now