mirror of
https://github.com/thp/pyotherside.git
synced 2025-01-28 23:52:55 +08:00
importNames, import specific objects from a module to Python's global space
The importNames and importNames_sync adopt the protocol of importModule. The importNames(module_name, [objects_names], callback) is asynchronous. It calls the synchronous importNames_sync(module_name, [object_names]) via the signal import_names. importNames_sync imports the module (with PyImport_ImportModule(moduleName)) and loops over the given names trying to get the corresponding object from the module (by PyObject_GetAttrString). On success the object is inserted into the global space of the Python interpreter. (priv->globals.borrow() is the pointer to the corresponding Python dict.) Each failed import separately emits the error message and continues to the next iteration. Changes to be committed: modified: src/qpython.cpp modified: src/qpython.h modified: src/qpython_worker.cpp modified: src/qpython_worker.h
This commit is contained in:
parent
4d3b4528b0
commit
8ad6d92bba
@ -62,6 +62,8 @@ QPython::QPython(QObject *parent, int api_version_major, int api_version_minor)
|
|||||||
|
|
||||||
QObject::connect(this, SIGNAL(import(QString,QJSValue *)),
|
QObject::connect(this, SIGNAL(import(QString,QJSValue *)),
|
||||||
worker, SLOT(import(QString,QJSValue *)));
|
worker, SLOT(import(QString,QJSValue *)));
|
||||||
|
QObject::connect(this, SIGNAL(import_names(QString, QVariant, QJSValue *)),
|
||||||
|
worker, SLOT(import_names(QString, QVariant, QJSValue *)));
|
||||||
QObject::connect(worker, SIGNAL(imported(bool,QJSValue *)),
|
QObject::connect(worker, SIGNAL(imported(bool,QJSValue *)),
|
||||||
this, SLOT(imported(bool,QJSValue *)));
|
this, SLOT(imported(bool,QJSValue *)));
|
||||||
|
|
||||||
@ -126,6 +128,67 @@ QPython::addImportPath(QString path)
|
|||||||
PyList_Insert(sys_path, 0, cwd.borrow());
|
PyList_Insert(sys_path, 0, cwd.borrow());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QPython::importNames(QString name, QVariant args, QJSValue callback)
|
||||||
|
{
|
||||||
|
QJSValue *cb = 0;
|
||||||
|
if (!callback.isNull() && !callback.isUndefined() && callback.isCallable()) {
|
||||||
|
cb = new QJSValue(callback);
|
||||||
|
}
|
||||||
|
emit import_names(name, args, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
QPython::importNames_sync(QString module_name, QVariant args)
|
||||||
|
{
|
||||||
|
// The plan is to "from module_name import a, b, c". And args is the list with a, b, c.
|
||||||
|
// The module_name can be a packaged module "x.y.z" -- "from x.y.z import a, b, c".
|
||||||
|
// Thus:
|
||||||
|
// - import the module, given by module_name,
|
||||||
|
// - get the objects from the module, given by names in args,
|
||||||
|
// - put the objects into globals of priv
|
||||||
|
|
||||||
|
QByteArray utf8bytes = module_name.toUtf8();
|
||||||
|
const char *moduleName = utf8bytes.constData();
|
||||||
|
|
||||||
|
ENSURE_GIL_STATE;
|
||||||
|
|
||||||
|
// PyOtherSide API 1.2 behavior: "import x.y.z" -- where the module 'z' is needed
|
||||||
|
PyObjectRef module = PyObjectRef(PyImport_ImportModule(moduleName), true);
|
||||||
|
|
||||||
|
if (!module) {
|
||||||
|
emitError(QString("Cannot import module: %1 (%2)").arg(module_name).arg(priv->formatExc()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// at this point the module with the target objects is in PyObjectRef module,
|
||||||
|
// it should be well imported in Python
|
||||||
|
|
||||||
|
// Get the names of functions/objects to import
|
||||||
|
QVariantList vl = args.toList();
|
||||||
|
|
||||||
|
QString obj_name; // object name to import
|
||||||
|
PyObjectRef result; // the object, obtained from globals_temp
|
||||||
|
|
||||||
|
// for each object name try to get it from the module
|
||||||
|
// - on success put it into priv.globals
|
||||||
|
// - on failure emit the error and continue
|
||||||
|
for (QVariantList::const_iterator obj = vl.begin(); obj != vl.end(); ++obj)
|
||||||
|
{
|
||||||
|
obj_name = obj->toString();
|
||||||
|
utf8bytes = obj_name.toUtf8();
|
||||||
|
PyObject *res = PyObject_GetAttrString(module.borrow(), utf8bytes);
|
||||||
|
result = PyObjectRef(res, true);
|
||||||
|
if (!result) {
|
||||||
|
emitError(QString("Object '%1' is not found in '%2': (%3)").arg(obj_name).arg(module_name).arg(priv->formatExc()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PyDict_SetItemString(priv->globals.borrow(), utf8bytes.constData(), result.borrow());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QPython::importModule(QString name, QJSValue callback)
|
QPython::importModule(QString name, QJSValue callback)
|
||||||
{
|
{
|
||||||
|
@ -130,6 +130,65 @@ class QPython : public QObject {
|
|||||||
Q_INVOKABLE QVariant
|
Q_INVOKABLE QVariant
|
||||||
evaluate(QString expr);
|
evaluate(QString expr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Asynchronously import objects from Python module
|
||||||
|
*
|
||||||
|
* Imports objects, given by list of names, from Python module asynchronously.
|
||||||
|
* The function will return immediately. If the module is successfully imported,
|
||||||
|
* the supplied \a callback will be called. Only then will the
|
||||||
|
* imported module be available:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* Python {
|
||||||
|
* Component.onCompleted: {
|
||||||
|
* importNames('os', ['path'], function (success) {
|
||||||
|
* if (success) {
|
||||||
|
* // You can use the "path" submodule here
|
||||||
|
* } else {
|
||||||
|
* console.log('Importing failed')
|
||||||
|
* }
|
||||||
|
* });
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* If an error occurs while trying to import, the signal error()
|
||||||
|
* will be emitted with detailed information about the error.
|
||||||
|
*
|
||||||
|
* \arg name The name of the Python module to import from
|
||||||
|
* \arg args The name of Python objects to import from the module
|
||||||
|
* \arg callback The JS callback to be called when the module is
|
||||||
|
* successfully imported
|
||||||
|
**/
|
||||||
|
Q_INVOKABLE void
|
||||||
|
importNames(QString name, QVariant args, QJSValue callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Synchronously import objects from Python module
|
||||||
|
*
|
||||||
|
* Imports objects, given by list of names, from Python module synchronously.
|
||||||
|
* This function will block until the objects are imported and available.
|
||||||
|
* In general, you should use importNames() instead of this function
|
||||||
|
* to avoid blocking the QML UI thread. Example use:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* Python {
|
||||||
|
* Component.onCompleted: {
|
||||||
|
* var success = importNames_sync('os', ['path']);
|
||||||
|
* if (success) {
|
||||||
|
* // You can use the "path" submodule here
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* \arg name The name of the Python module to import from
|
||||||
|
* \arg args The name of Python objects to import from the module
|
||||||
|
* \result \c true if the import was successful, \c false otherwise
|
||||||
|
**/
|
||||||
|
Q_INVOKABLE bool
|
||||||
|
importNames_sync(QString name, QVariant args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Asynchronously import a Python module
|
* \brief Asynchronously import a Python module
|
||||||
*
|
*
|
||||||
@ -304,6 +363,7 @@ class QPython : public QObject {
|
|||||||
/* For internal use only */
|
/* For internal use only */
|
||||||
void process(QVariant func, QVariant args, QJSValue *callback);
|
void process(QVariant func, QVariant args, QJSValue *callback);
|
||||||
void import(QString name, QJSValue *callback);
|
void import(QString name, QJSValue *callback);
|
||||||
|
void import_names(QString name, QVariant args, QJSValue *callback);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void receive(QVariant data);
|
void receive(QVariant data);
|
||||||
|
@ -48,3 +48,12 @@ QPythonWorker::import(QString name, QJSValue *callback)
|
|||||||
emit imported(result, callback);
|
emit imported(result, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QPythonWorker::import_names(QString name, QVariant args, QJSValue *callback)
|
||||||
|
{
|
||||||
|
bool result = qpython->importNames_sync(name, args);
|
||||||
|
if (callback) {
|
||||||
|
emit imported(result, callback); // using the same imported signal at the end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -36,6 +36,7 @@ class QPythonWorker : public QObject {
|
|||||||
public slots:
|
public slots:
|
||||||
void process(QVariant func, QVariant args, QJSValue *callback);
|
void process(QVariant func, QVariant args, QJSValue *callback);
|
||||||
void import(QString func, QJSValue *callback);
|
void import(QString func, QJSValue *callback);
|
||||||
|
void import_names(QString func, QVariant args, QJSValue *callback);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished(QVariant result, QJSValue *callback);
|
void finished(QVariant result, QJSValue *callback);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user