mirror of
https://github.com/thp/pyotherside.git
synced 2025-01-28 23:52:55 +08:00
Fix call_sync when used with parameters
Factor out the unboxing in call() to a separate method. To handle direct calls to call_sync(), rename the implementation of call_sync() to call_internal() and add a call_sync() stub that calls call_internal(). call_internal() can now takes a boolean "unbox" parameter without impacting the formal interfaces that call() and call_sync() provide to QML users. If the "unbox" parameter is true, it unboxes the arguments first. If false, it doesn't. Now call_sync() can call call_internal() requesting unboxing. call() can also do the unboxing itself, and then later process() (the slot for switching call() to a different thread) can call call_internal() requesting no unboxing. Since we now have and must keep track of two versions of the parameters (boxed vs. unboxed), I also rename these parameters to keep things explicit and clear. Here's what was going wrong before: call() was unboxing QJSValue elements inside the argument list into plain QVariants, and then calling (indirectly, to switch threads) call_sync(). call_sync() did no such unboxing. Since call_sync() is exposed directly as an entry point, this meant that priv->call(), which appears to expect unboxed argument lists, was failing in this case. There is a comment noting that call() should do the unboxing in the GUI thread so should not defer it. So the unboxing has to happen in two different places depending on whether the user called call() or call_sync(). Fixes: #49
This commit is contained in:
parent
77738b5a76
commit
260c9c275c
@ -298,15 +298,10 @@ QPython::evaluate(QString expr)
|
||||
return convertPyObjectToQVariant(o.borrow());
|
||||
}
|
||||
|
||||
void
|
||||
QPython::call(QVariant func, QVariant args, QJSValue callback)
|
||||
QVariantList
|
||||
QPython::unboxArgList(QVariant &args)
|
||||
{
|
||||
QJSValue *cb = 0;
|
||||
if (!callback.isNull() && !callback.isUndefined() && callback.isCallable()) {
|
||||
cb = new QJSValue(callback);
|
||||
}
|
||||
// Unbox QJSValue from QVariant, since QJSValue::toVariant() can cause calls into
|
||||
// QML engine and we don't want that to happen from non-GUI thread
|
||||
// Unbox QJSValue from QVariant
|
||||
QVariantList vl = args.toList();
|
||||
for (int i = 0, c = vl.count(); i < c; ++i) {
|
||||
QVariant &v = vl[i];
|
||||
@ -315,11 +310,31 @@ QPython::call(QVariant func, QVariant args, QJSValue callback)
|
||||
v = v.value<QJSValue>().toVariant();
|
||||
}
|
||||
}
|
||||
emit process(func, vl, cb);
|
||||
return vl;
|
||||
}
|
||||
|
||||
void
|
||||
QPython::call(QVariant func, QVariant boxed_args, QJSValue callback)
|
||||
{
|
||||
QJSValue *cb = 0;
|
||||
if (!callback.isNull() && !callback.isUndefined() && callback.isCallable()) {
|
||||
cb = new QJSValue(callback);
|
||||
}
|
||||
// Unbox QJSValue from QVariant, since QJSValue::toVariant() can cause calls into
|
||||
// QML engine and we don't want that to happen from non-GUI thread
|
||||
QVariantList unboxed_args = unboxArgList(boxed_args);
|
||||
|
||||
emit process(func, unboxed_args, cb);
|
||||
}
|
||||
|
||||
QVariant
|
||||
QPython::call_sync(QVariant func, QVariant args)
|
||||
QPython::call_sync(QVariant func, QVariant boxed_args)
|
||||
{
|
||||
return call_internal(func, boxed_args, true);
|
||||
}
|
||||
|
||||
QVariant
|
||||
QPython::call_internal(QVariant func, QVariant args, bool unbox)
|
||||
{
|
||||
ENSURE_GIL_STATE;
|
||||
|
||||
@ -348,8 +363,18 @@ QPython::call_sync(QVariant func, QVariant args)
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
// Unbox QJSValue from QVariant if requested. QPython::call may have done
|
||||
// this already, but call_sync is also exposed directly, so it does not
|
||||
// happen in this case otherwise
|
||||
QVariant args_unboxed;
|
||||
if (unbox) {
|
||||
args_unboxed = unboxArgList(args);
|
||||
} else {
|
||||
args_unboxed = args;
|
||||
}
|
||||
|
||||
QVariant v;
|
||||
QString errorMessage = priv->call(callable.borrow(), name, args, &v);
|
||||
QString errorMessage = priv->call(callable.borrow(), name, args_unboxed, &v);
|
||||
if (!errorMessage.isNull()) {
|
||||
emitError(errorMessage);
|
||||
}
|
||||
|
@ -297,7 +297,11 @@ class QPython : public QObject {
|
||||
* \result The return value of the Python call as Qt data type
|
||||
**/
|
||||
Q_INVOKABLE QVariant
|
||||
call_sync(QVariant func, QVariant args=QVariantList());
|
||||
call_sync(QVariant func, QVariant boxed_args=QVariantList());
|
||||
|
||||
QVariant
|
||||
call_internal(QVariant func, QVariant boxed_args=QVariantList(),
|
||||
bool unbox=true);
|
||||
|
||||
/**
|
||||
* \brief Get an attribute value of a Python object synchronously
|
||||
@ -361,7 +365,7 @@ class QPython : public QObject {
|
||||
void error(QString traceback);
|
||||
|
||||
/* For internal use only */
|
||||
void process(QVariant func, QVariant args, QJSValue *callback);
|
||||
void process(QVariant func, QVariant unboxed_args, QJSValue *callback);
|
||||
void import(QString name, QJSValue *callback);
|
||||
void import_names(QString name, QVariant args, QJSValue *callback);
|
||||
|
||||
@ -375,6 +379,8 @@ class QPython : public QObject {
|
||||
void disconnectNotify(const QMetaMethod &signal);
|
||||
|
||||
private:
|
||||
QVariantList unboxArgList(QVariant &args);
|
||||
|
||||
static QPythonPriv *priv;
|
||||
|
||||
QPythonWorker *worker;
|
||||
|
@ -32,9 +32,9 @@ QPythonWorker::~QPythonWorker()
|
||||
}
|
||||
|
||||
void
|
||||
QPythonWorker::process(QVariant func, QVariant args, QJSValue *callback)
|
||||
QPythonWorker::process(QVariant func, QVariant unboxed_args, QJSValue *callback)
|
||||
{
|
||||
QVariant result = qpython->call_sync(func, args);
|
||||
QVariant result = qpython->call_internal(func, unboxed_args, false);
|
||||
if (callback) {
|
||||
emit finished(result, callback);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class QPythonWorker : public QObject {
|
||||
~QPythonWorker();
|
||||
|
||||
public slots:
|
||||
void process(QVariant func, QVariant args, QJSValue *callback);
|
||||
void process(QVariant func, QVariant unboxed_args, QJSValue *callback);
|
||||
void import(QString func, QJSValue *callback);
|
||||
void import_names(QString func, QVariant args, QJSValue *callback);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user