##// 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 #include "PythonQtImporter.h"
47 #include "PythonQtImporter.h"
48 #include "PythonQtImportFileInterface.h"
48 #include "PythonQtImportFileInterface.h"
49 #include "PythonQt.h"
49 #include "PythonQt.h"
50 #include "PythonQtConversion.h"
50 #include <QFile>
51 #include <QFile>
51 #include <QFileInfo>
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 QString subname;
94 QString subname;
93 struct st_mlab_searchorder *zso;
95 struct st_mlab_searchorder *zso;
94
96
@@ -99,16 +101,22 PythonQtImport::module_info PythonQtImport::getModuleInfo(PythonQtImporter* self
99 for (zso = mlab_searchorder; *zso->suffix; zso++) {
101 for (zso = mlab_searchorder; *zso->suffix; zso++) {
100 test = path + zso->suffix;
102 test = path + zso->suffix;
101 if (PythonQt::importInterface()->exists(test)) {
103 if (PythonQt::importInterface()->exists(test)) {
102 if (zso->type & IS_PACKAGE)
104 info.fullPath = test;
103 return MI_PACKAGE;
105 info.moduleName = subname;
104 else
106 info.type = (zso->type & IS_PACKAGE)?MI_PACKAGE:MI_MODULE;
105 return MI_MODULE;
107 return info;
106 }
108 }
107 }
109 }
108 if (PythonQt::importInterface()->exists(path+".so")) {
110 // test if it is a shared library
109 return MI_SHAREDLIBRARY;
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 &fullname, &path))
175 &fullname, &path))
168 return NULL;
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);
180 PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname);
173
181 if (info.type != PythonQtImport::MI_NOT_FOUND) {
174 PythonQtImport::module_info info = PythonQtImport::getModuleInfo(self, fullname);
175 if (info == PythonQtImport::MI_MODULE || info == PythonQtImport::MI_PACKAGE ||
176 info== PythonQtImport::MI_SHAREDLIBRARY) {
177 Py_INCREF(self);
182 Py_INCREF(self);
178 return (PyObject *)self;
183 return (PyObject *)self;
179 } else {
184 } else {
@@ -187,16 +192,21 PyObject *
187 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
192 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
188 {
193 {
189 PythonQtImporter *self = (PythonQtImporter *)obj;
194 PythonQtImporter *self = (PythonQtImporter *)obj;
190 PyObject *code, *mod, *dict;
195 PyObject *code = NULL, *mod = NULL, *dict = NULL;
191 char *fullname;
196 char *fullname;
192 QString modpath;
193 int ispackage;
194
197
195 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.load_module",
198 if (!PyArg_ParseTuple(args, "s:PythonQtImporter.load_module",
196 &fullname))
199 &fullname))
197 return NULL;
200 return NULL;
198
201
199 code = PythonQtImport::getModuleCode(self, fullname, &ispackage, modpath);
202 PythonQtImport::ModuleInfo info = PythonQtImport::getModuleInfo(self, fullname);
203 if (info.type == PythonQtImport::MI_NOT_FOUND) {
204 return NULL;
205 }
206
207 if (info.type == PythonQtImport::MI_PACKAGE || info.type == PythonQtImport::MI_MODULE) {
208 QString fullPath;
209 code = PythonQtImport::getModuleCode(self, fullname, fullPath);
200 if (code == NULL) {
210 if (code == NULL) {
201 return NULL;
211 return NULL;
202 }
212 }
@@ -214,9 +224,9 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
214 return NULL;
224 return NULL;
215 }
225 }
216
226
217 if (ispackage) {
227 if (info.type == PythonQtImport::MI_PACKAGE) {
218 PyObject *pkgpath, *fullpath;
228 PyObject *pkgpath, *fullpath;
219 QString subname = PythonQtImport::getSubName(fullname);
229 QString subname = info.moduleName;
220 int err;
230 int err;
221
231
222 fullpath = PyString_FromFormat("%s%c%s",
232 fullpath = PyString_FromFormat("%s%c%s",
@@ -244,11 +254,45 PythonQtImporter_load_module(PyObject *obj, PyObject *args)
244 return NULL;
254 return NULL;
245 }
255 }
246 }
256 }
247 mod = PyImport_ExecCodeModuleEx(fullname, code, (char*)modpath.toLatin1().data());
257 mod = PyImport_ExecCodeModuleEx(fullname, code, fullPath.toLatin1().data());
248 Py_DECREF(code);
258 Py_DECREF(code);
249 if (Py_VerboseFlag) {
259 if (Py_VerboseFlag) {
250 PySys_WriteStderr("import %s # loaded from %s\n",
260 PySys_WriteStderr("import %s # loaded from %s\n",
251 fullname, modpath.toLatin1().constData());
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 return mod;
297 return mod;
254 }
298 }
@@ -271,51 +315,13 PythonQtImporter_get_code(PyObject *obj, PyObject *args)
271 return NULL;
315 return NULL;
272
316
273 QString notused;
317 QString notused;
274 return PythonQtImport::getModuleCode(self, fullname, NULL, notused);
318 return PythonQtImport::getModuleCode(self, fullname, notused);
275 }
319 }
276
320
277 PyObject *
321 PyObject *
278 PythonQtImporter_get_source(PyObject * /*obj*/, PyObject * /*args*/)
322 PythonQtImporter_get_source(PyObject * /*obj*/, PyObject * /*args*/)
279 {
323 {
280 // EXTRA, NOT YET IMPLEMENTED
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 return NULL;
325 return NULL;
320 }
326 }
321
327
@@ -648,8 +654,7 PythonQtImport::getMTimeOfSource(const QString& path)
648 /* Get the code object associated with the module specified by
654 /* Get the code object associated with the module specified by
649 'fullname'. */
655 'fullname'. */
650 PyObject *
656 PyObject *
651 PythonQtImport::getModuleCode(PythonQtImporter *self, char *fullname,
657 PythonQtImport::getModuleCode(PythonQtImporter *self, const char* fullname, QString& modpath)
652 int *p_ispackage, QString& modpath)
653 {
658 {
654 QString subname;
659 QString subname;
655 struct st_mlab_searchorder *zso;
660 struct st_mlab_searchorder *zso;
@@ -670,17 +675,17 PythonQtImport::getModuleCode(PythonQtImporter *self, char *fullname,
670 int ispackage = zso->type & IS_PACKAGE;
675 int ispackage = zso->type & IS_PACKAGE;
671 int isbytecode = zso->type & IS_BYTECODE;
676 int isbytecode = zso->type & IS_BYTECODE;
672
677
673 if (isbytecode)
678 if (isbytecode) {
674 mtime = getMTimeOfSource(test);
679 mtime = getMTimeOfSource(test);
675 if (p_ispackage != NULL)
680 }
676 *p_ispackage = ispackage;
677 code = getCodeFromData(test, isbytecode, ispackage, mtime);
681 code = getCodeFromData(test, isbytecode, ispackage, mtime);
678 if (code == Py_None) {
682 if (code == Py_None) {
679 Py_DECREF(code);
683 Py_DECREF(code);
680 continue;
684 continue;
681 }
685 }
682 if (code != NULL)
686 if (code != NULL) {
683 modpath = test;
687 modpath = test;
688 }
684 return code;
689 return code;
685 }
690 }
686 }
691 }
@@ -66,14 +66,23 typedef struct _PythonQtImporter {
66 class PythonQtImport
66 class PythonQtImport
67 {
67 {
68 public:
68 public:
69 enum module_info {
69
70 MI_ERROR,
70 enum ModuleType {
71 MI_NOT_FOUND,
71 MI_NOT_FOUND,
72 MI_MODULE,
72 MI_MODULE,
73 MI_PACKAGE,
73 MI_PACKAGE,
74 MI_SHAREDLIBRARY
74 MI_SHAREDLIBRARY
75 };
75 };
76
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;
84 };
85
77 //! initialize
86 //! initialize
78 static void init();
87 static void init();
79
88
@@ -98,15 +107,15 public:
98
107
99 //! Get the code object associated with the module specified by
108 //! Get the code object associated with the module specified by
100 //! 'fullname'.
109 //! 'fullname'.
101 static PyObject * getModuleCode(PythonQtImporter *self, char *fullname,
110 static PyObject * getModuleCode(PythonQtImporter *self,
102 int *p_ispackage, QString& modpath);
111 const char* fullname, QString& modpath);
103
112
104
113
105 //! gets the compiled code for the given *.py file if there is a valid pyc file, otherwise compiles the file and writes the pyc
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 static PyObject* getCodeFromPyc(const QString& file);
115 static PyObject* getCodeFromPyc(const QString& file);
107
116
108 //! Return if module exists and is a package or a module
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 //! get the last name of a dot chain (first.second.last)
120 //! get the last name of a dot chain (first.second.last)
112 static QString getSubName(const QString& str);
121 static QString getSubName(const QString& str);
General Comments 0
You need to be logged in to leave comments. Login now