mirror of
https://github.com/thp/pyotherside.git
synced 2025-01-28 23:52:55 +08:00
Print unhandled errors to the console
This commit is contained in:
parent
eccdad94ee
commit
21b416a01e
@ -63,6 +63,9 @@ io.thp.pyotherside 1.4
|
|||||||
* :func:`call` and :func:`call_sync` now accept a Python callable object
|
* :func:`call` and :func:`call_sync` now accept a Python callable object
|
||||||
for the first parameter (previously, only strings were supported)
|
for the first parameter (previously, only strings were supported)
|
||||||
|
|
||||||
|
* If :func:`error` doesn't have a handler defined, error messages will be
|
||||||
|
printed to the console as warnings
|
||||||
|
|
||||||
|
|
||||||
QML ``Python`` Element
|
QML ``Python`` Element
|
||||||
----------------------
|
----------------------
|
||||||
@ -90,6 +93,12 @@ Signals
|
|||||||
|
|
||||||
Error handler for errors from Python.
|
Error handler for errors from Python.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.4.0
|
||||||
|
If the error signal is not connected, PyOtherSide will print the
|
||||||
|
error as QWarning on the console (previously, error messages
|
||||||
|
were only shown if the signal was connected and printed there).
|
||||||
|
To avoid printing the error, just define a no-op handler.
|
||||||
|
|
||||||
Methods
|
Methods
|
||||||
```````
|
```````
|
||||||
|
|
||||||
@ -985,6 +994,8 @@ Version 1.4.0 (UNRELEASED)
|
|||||||
* :func:`call` and :func:`call_sync` now also accept a Python callable as
|
* :func:`call` and :func:`call_sync` now also accept a Python callable as
|
||||||
first argument
|
first argument
|
||||||
* Support for `Accessing QObjects from Python`_ (properties and slots)
|
* Support for `Accessing QObjects from Python`_ (properties and slots)
|
||||||
|
* Print error messages to the console if :func:`error` doesn't have any
|
||||||
|
handlers connected
|
||||||
|
|
||||||
Version 1.3.0 (2014-07-24)
|
Version 1.3.0 (2014-07-24)
|
||||||
--------------------------
|
--------------------------
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include <QJSEngine>
|
#include <QJSEngine>
|
||||||
|
#include <QMetaMethod>
|
||||||
|
|
||||||
|
|
||||||
#define SINCE_API_VERSION(smaj, smin) \
|
#define SINCE_API_VERSION(smaj, smin) \
|
||||||
@ -43,6 +44,7 @@ QPython::QPython(QObject *parent, int api_version_major, int api_version_minor)
|
|||||||
, handlers()
|
, handlers()
|
||||||
, api_version_major(api_version_major)
|
, api_version_major(api_version_major)
|
||||||
, api_version_minor(api_version_minor)
|
, api_version_minor(api_version_minor)
|
||||||
|
, error_connections(0)
|
||||||
{
|
{
|
||||||
if (priv == NULL) {
|
if (priv == NULL) {
|
||||||
priv = new QPythonPriv;
|
priv = new QPythonPriv;
|
||||||
@ -75,6 +77,22 @@ QPython::~QPython()
|
|||||||
delete worker;
|
delete worker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QPython::connectNotify(const QMetaMethod &signal)
|
||||||
|
{
|
||||||
|
if (signal == QMetaMethod::fromSignal(&QPython::error)) {
|
||||||
|
error_connections++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QPython::disconnectNotify(const QMetaMethod &signal)
|
||||||
|
{
|
||||||
|
if (signal == QMetaMethod::fromSignal(&QPython::error)) {
|
||||||
|
error_connections--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QPython::addImportPath(QString path)
|
QPython::addImportPath(QString path)
|
||||||
{
|
{
|
||||||
@ -96,7 +114,7 @@ QPython::addImportPath(QString path)
|
|||||||
QString filename = "/io/thp/pyotherside/qrc_importer.py";
|
QString filename = "/io/thp/pyotherside/qrc_importer.py";
|
||||||
QString errorMessage = priv->importFromQRC(module, filename);
|
QString errorMessage = priv->importFromQRC(module, filename);
|
||||||
if (!errorMessage.isNull()) {
|
if (!errorMessage.isNull()) {
|
||||||
emit error(errorMessage);
|
emitError(errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +163,7 @@ QPython::importModule_sync(QString name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!module) {
|
if (!module) {
|
||||||
emit error(QString("Cannot import module: %1 (%2)").arg(name).arg(priv->formatExc()));
|
emitError(QString("Cannot import module: %1 (%2)").arg(name).arg(priv->formatExc()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +200,7 @@ QPython::receive(QVariant variant)
|
|||||||
// call is asynchronous (it returns before we call into JS), so do
|
// call is asynchronous (it returns before we call into JS), so do
|
||||||
// the next best thing and report the error to our error handler in
|
// the next best thing and report the error to our error handler in
|
||||||
// QML instead.
|
// QML instead.
|
||||||
emit error("pyotherside.send() failed handler: " +
|
emitError("pyotherside.send() failed handler: " +
|
||||||
result.property("fileName").toString() + ":" +
|
result.property("fileName").toString() + ":" +
|
||||||
result.property("lineNumber").toString() + ": " +
|
result.property("lineNumber").toString() + ": " +
|
||||||
result.toString());
|
result.toString());
|
||||||
@ -210,7 +228,7 @@ QPython::evaluate(QString expr)
|
|||||||
|
|
||||||
PyObjectRef o(priv->eval(expr), true);
|
PyObjectRef o(priv->eval(expr), true);
|
||||||
if (!o) {
|
if (!o) {
|
||||||
emit error(QString("Cannot evaluate '%1' (%2)").arg(expr).arg(priv->formatExc()));
|
emitError(QString("Cannot evaluate '%1' (%2)").arg(expr).arg(priv->formatExc()));
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,29 +251,34 @@ QPython::call_sync(QVariant func, QVariant args)
|
|||||||
ENSURE_GIL_STATE;
|
ENSURE_GIL_STATE;
|
||||||
|
|
||||||
PyObjectRef callable;
|
PyObjectRef callable;
|
||||||
|
QString name;
|
||||||
|
|
||||||
if (SINCE_API_VERSION(1, 4)) {
|
if (SINCE_API_VERSION(1, 4)) {
|
||||||
if (static_cast<QMetaType::Type>(func.type()) == QMetaType::QString) {
|
if (static_cast<QMetaType::Type>(func.type()) == QMetaType::QString) {
|
||||||
// Using version >= 1.4, but func is a string
|
// Using version >= 1.4, but func is a string
|
||||||
callable = PyObjectRef(priv->eval(func.toString()), true);
|
callable = PyObjectRef(priv->eval(func.toString()), true);
|
||||||
|
name = func.toString();
|
||||||
} else {
|
} else {
|
||||||
// Try to interpret "func" as a Python object
|
// Try to interpret "func" as a Python object
|
||||||
callable = PyObjectRef(convertQVariantToPyObject(func), true);
|
callable = PyObjectRef(convertQVariantToPyObject(func), true);
|
||||||
|
PyObjectRef repr = PyObjectRef(PyObject_Repr(callable.borrow()), true);
|
||||||
|
name = convertPyObjectToQVariant(repr.borrow()).toString();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Versions before 1.4 only support func as a string
|
// Versions before 1.4 only support func as a string
|
||||||
callable = PyObjectRef(priv->eval(func.toString()), true);
|
callable = PyObjectRef(priv->eval(func.toString()), true);
|
||||||
|
name = func.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!callable) {
|
if (!callable) {
|
||||||
emit error(QString("Function not found: '%1' (%2)").arg(func.toString()).arg(priv->formatExc()));
|
emitError(QString("Function not found: '%1' (%2)").arg(name).arg(priv->formatExc()));
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant v;
|
QVariant v;
|
||||||
QString errorMessage = priv->call(callable.borrow(), func.toString(), args, &v);
|
QString errorMessage = priv->call(callable.borrow(), name, args, &v);
|
||||||
if (!errorMessage.isNull()) {
|
if (!errorMessage.isNull()) {
|
||||||
emit error(errorMessage);
|
emitError(errorMessage);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@ -263,7 +286,7 @@ QPython::call_sync(QVariant func, QVariant args)
|
|||||||
QVariant
|
QVariant
|
||||||
QPython::getattr(QVariant obj, QString attr) {
|
QPython::getattr(QVariant obj, QString attr) {
|
||||||
if (!SINCE_API_VERSION(1, 4)) {
|
if (!SINCE_API_VERSION(1, 4)) {
|
||||||
emit error(QString("Import PyOtherSide 1.4 or newer to use getattr()"));
|
emitError(QString("Import PyOtherSide 1.4 or newer to use getattr()"));
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,7 +295,7 @@ QPython::getattr(QVariant obj, QString attr) {
|
|||||||
PyObjectRef pyobj(convertQVariantToPyObject(obj), true);
|
PyObjectRef pyobj(convertQVariantToPyObject(obj), true);
|
||||||
|
|
||||||
if (!pyobj) {
|
if (!pyobj) {
|
||||||
emit error(QString("Failed to convert %1 to python object: '%1' (%2)").arg(obj.toString()).arg(priv->formatExc()));
|
emitError(QString("Failed to convert %1 to python object: '%1' (%2)").arg(obj.toString()).arg(priv->formatExc()));
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,7 +305,7 @@ QPython::getattr(QVariant obj, QString attr) {
|
|||||||
PyObjectRef o(PyObject_GetAttrString(pyobj.borrow(), attrStr), true);
|
PyObjectRef o(PyObject_GetAttrString(pyobj.borrow(), attrStr), true);
|
||||||
|
|
||||||
if (!o) {
|
if (!o) {
|
||||||
emit error(QString("Attribute not found: '%1' (%2)").arg(attr).arg(priv->formatExc()));
|
emitError(QString("Attribute not found: '%1' (%2)").arg(attr).arg(priv->formatExc()));
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +321,7 @@ QPython::finished(QVariant result, QJSValue *callback)
|
|||||||
QJSValue callbackResult = callback->call(args);
|
QJSValue callbackResult = callback->call(args);
|
||||||
if (SINCE_API_VERSION(1, 2)) {
|
if (SINCE_API_VERSION(1, 2)) {
|
||||||
if (callbackResult.isError()) {
|
if (callbackResult.isError()) {
|
||||||
emit error(callbackResult.property("fileName").toString() + ":" +
|
emitError(callbackResult.property("fileName").toString() + ":" +
|
||||||
callbackResult.property("lineNumber").toString() + ": " +
|
callbackResult.property("lineNumber").toString() + ": " +
|
||||||
callbackResult.toString());
|
callbackResult.toString());
|
||||||
}
|
}
|
||||||
@ -315,7 +338,7 @@ QPython::imported(bool result, QJSValue *callback)
|
|||||||
QJSValue callbackResult = callback->call(args);
|
QJSValue callbackResult = callback->call(args);
|
||||||
if (SINCE_API_VERSION(1, 2)) {
|
if (SINCE_API_VERSION(1, 2)) {
|
||||||
if (callbackResult.isError()) {
|
if (callbackResult.isError()) {
|
||||||
emit error(callbackResult.property("fileName").toString() + ":" +
|
emitError(callbackResult.property("fileName").toString() + ":" +
|
||||||
callbackResult.property("lineNumber").toString() + ": " +
|
callbackResult.property("lineNumber").toString() + ": " +
|
||||||
callbackResult.toString());
|
callbackResult.toString());
|
||||||
}
|
}
|
||||||
@ -334,3 +357,16 @@ QPython::pythonVersion()
|
|||||||
{
|
{
|
||||||
return QString(PY_VERSION);
|
return QString(PY_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QPython::emitError(const QString &message)
|
||||||
|
{
|
||||||
|
if (error_connections) {
|
||||||
|
emit error(message);
|
||||||
|
} else {
|
||||||
|
// We should only print the error if SINCE_API_VERSION(1, 4), but as
|
||||||
|
// the error messages are useful for debugging (especially if users
|
||||||
|
// don't import the latest API version), we do it unconditionally
|
||||||
|
qWarning("Unhandled PyOtherSide error: %s", message.toUtf8().constData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -311,6 +311,9 @@ class QPython : public QObject {
|
|||||||
void finished(QVariant result, QJSValue *callback);
|
void finished(QVariant result, QJSValue *callback);
|
||||||
void imported(bool result, QJSValue *callback);
|
void imported(bool result, QJSValue *callback);
|
||||||
|
|
||||||
|
void connectNotify(const QMetaMethod &signal);
|
||||||
|
void disconnectNotify(const QMetaMethod &signal);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static QPythonPriv *priv;
|
static QPythonPriv *priv;
|
||||||
|
|
||||||
@ -320,6 +323,9 @@ class QPython : public QObject {
|
|||||||
|
|
||||||
int api_version_major;
|
int api_version_major;
|
||||||
int api_version_minor;
|
int api_version_minor;
|
||||||
|
|
||||||
|
void emitError(const QString &message);
|
||||||
|
int error_connections;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QPython10 : public QPython {
|
class QPython10 : public QPython {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user