more work
This commit is contained in:
parent
59c1c8e9f2
commit
f97e5bf4d0
151
libnymea-core/integrations/python/pyparam.h
Normal file
151
libnymea-core/integrations/python/pyparam.h
Normal file
@ -0,0 +1,151 @@
|
||||
#ifndef PYPARAM_H
|
||||
#define PYPARAM_H
|
||||
|
||||
#include <Python.h>
|
||||
#include "structmember.h"
|
||||
|
||||
#include "types/param.h"
|
||||
|
||||
#include "loggingcategories.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
||||
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||
|
||||
|
||||
typedef struct _pyparam {
|
||||
PyObject_HEAD
|
||||
PyObject* pyParamTypeId = nullptr;
|
||||
PyObject* pyValue = nullptr;
|
||||
} PyParam;
|
||||
|
||||
static void PyParam_dealloc(PyParam * self) {
|
||||
// FIXME: Why is this not called? Seems we're leaking...
|
||||
Q_ASSERT(false);
|
||||
Py_XDECREF(self->pyParamTypeId);
|
||||
Py_XDECREF(self->pyValue);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
static PyMethodDef PyParam_methods[] = {
|
||||
{nullptr, nullptr, 0, nullptr} // sentinel
|
||||
};
|
||||
|
||||
static PyMemberDef PyParam_members[] = {
|
||||
{"paramTypeId", T_OBJECT_EX, offsetof(PyParam, pyParamTypeId), 0, "Param type ID"},
|
||||
{"value", T_OBJECT_EX, offsetof(PyParam, pyValue), 0, "Param value"},
|
||||
{nullptr, 0, 0, 0, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
static int PyParam_init(PyParam *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static char *kwlist[] = {"paramTypeId", "value", nullptr};
|
||||
PyObject *paramTypeId = nullptr, *value = nullptr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, ¶mTypeId, &value))
|
||||
return -1;
|
||||
|
||||
if (paramTypeId) {
|
||||
Py_XDECREF(self->pyParamTypeId);
|
||||
Py_INCREF(paramTypeId);
|
||||
self->pyParamTypeId = paramTypeId;
|
||||
}
|
||||
if (value) {
|
||||
Py_XDECREF(self->pyValue);
|
||||
Py_INCREF(value);
|
||||
self->pyValue = value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyTypeObject PyParamType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"nymea.Param", /* tp_name */
|
||||
sizeof(PyParam), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)PyParam_dealloc,/* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static PyParam* PyParam_fromParam(const Param ¶m)
|
||||
{
|
||||
PyParam *pyParam = PyObject_New(PyParam, &PyParamType);
|
||||
pyParam->pyParamTypeId = PyUnicode_FromString(param.paramTypeId().toString().toUtf8());
|
||||
|
||||
switch (param.value().type()) {
|
||||
case QVariant::Bool:
|
||||
pyParam->pyValue = PyBool_FromLong(*(long*)param.value().data());
|
||||
break;
|
||||
case QVariant::Int:
|
||||
case QVariant::UInt:
|
||||
case QVariant::LongLong:
|
||||
case QVariant::ULongLong:
|
||||
pyParam->pyValue = PyLong_FromLong(*(long*)param.value().data());
|
||||
break;
|
||||
case QVariant::String:
|
||||
case QVariant::ByteArray:
|
||||
pyParam->pyValue = PyUnicode_FromString(param.value().toString().toUtf8());
|
||||
break;
|
||||
case QVariant::Double:
|
||||
pyParam->pyValue = PyFloat_FromDouble(param.value().toDouble());
|
||||
break;
|
||||
case QVariant::Invalid:
|
||||
pyParam->pyValue = Py_None;
|
||||
Py_INCREF(pyParam->pyValue);
|
||||
break;
|
||||
default:
|
||||
qCWarning(dcThingManager) << "Unhandled data type in conversion from Param to PyParam!";
|
||||
pyParam->pyValue = Py_None;
|
||||
Py_INCREF(pyParam->pyValue);
|
||||
break;
|
||||
}
|
||||
return pyParam;
|
||||
}
|
||||
|
||||
static PyObject* PyParam_FromParamList(const ParamList ¶ms)
|
||||
{
|
||||
PyObject* result = PyTuple_New(params.count());
|
||||
for (int i = 0; i < params.count(); i++) {
|
||||
PyTuple_SET_ITEM(result, i, (PyObject*)PyParam_fromParam(params.at(i)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void registerParamType(PyObject *module)
|
||||
{
|
||||
PyParamType.tp_new = PyType_GenericNew;
|
||||
PyParamType.tp_basicsize = sizeof(PyParam);
|
||||
PyParamType.tp_dealloc=(destructor) PyParam_dealloc;
|
||||
PyParamType.tp_flags = Py_TPFLAGS_DEFAULT;
|
||||
PyParamType.tp_doc = "Param class";
|
||||
PyParamType.tp_methods = PyParam_methods;
|
||||
PyParamType.tp_members = PyParam_members;
|
||||
PyParamType.tp_init = reinterpret_cast<initproc>(PyParam_init);
|
||||
|
||||
if (PyType_Ready(&PyParamType) < 0) {
|
||||
return;
|
||||
}
|
||||
PyModule_AddObject(module, "Param", reinterpret_cast<PyObject*>(&PyParamType));
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#endif // PYPARAM_H
|
||||
@ -4,6 +4,8 @@
|
||||
#include <Python.h>
|
||||
#include "structmember.h"
|
||||
|
||||
#include "pyparam.h"
|
||||
|
||||
#include "integrations/thing.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
@ -15,7 +17,7 @@
|
||||
|
||||
typedef struct _thing {
|
||||
PyObject_HEAD
|
||||
Thing *ptrObj;
|
||||
Thing *thing;
|
||||
} PyThing;
|
||||
|
||||
|
||||
@ -25,26 +27,24 @@ static int PyThing_init(PyThing */*self*/, PyObject */*args*/, PyObject */*kwds*
|
||||
|
||||
|
||||
static void PyThing_dealloc(PyThing * self) {
|
||||
// FIXME: Why is this not called? Seems we're leaking...
|
||||
Q_ASSERT(false);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
static PyObject *PyThing_getName(PyThing *self, void */*closure*/)
|
||||
{
|
||||
if (!self->ptrObj) {
|
||||
if (!self->thing) {
|
||||
PyErr_SetString(PyExc_ValueError, "Thing has been removed from the system.");
|
||||
return nullptr;
|
||||
}
|
||||
// FIXME: Needs blocking queued connection
|
||||
PyObject *ret = PyUnicode_FromString(self->ptrObj->name().toUtf8().data());
|
||||
PyObject *ret = PyUnicode_FromString(self->thing->name().toUtf8().data());
|
||||
Py_INCREF(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int PyThing_setName(PyThing *self, PyObject *value, void */*closure*/){
|
||||
// FIXME: Needs queued connection
|
||||
self->ptrObj->setName(QString(PyUnicode_AsUTF8(value)));
|
||||
self->thing->setName(QString(PyUnicode_AsUTF8(value)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -67,8 +67,8 @@ static PyObject * PyThing_setStateValue(PyThing* self, PyObject* args)
|
||||
|
||||
QVariant value(bytes);
|
||||
|
||||
if (self->ptrObj != nullptr) {
|
||||
QMetaObject::invokeMethod(self->ptrObj, "setStateValue", Qt::QueuedConnection, Q_ARG(StateTypeId, stateTypeId), Q_ARG(QVariant, value));
|
||||
if (self->thing != nullptr) {
|
||||
QMetaObject::invokeMethod(self->thing, "setStateValue", Qt::QueuedConnection, Q_ARG(StateTypeId, stateTypeId), Q_ARG(QVariant, value));
|
||||
}
|
||||
|
||||
Py_XDECREF(repr);
|
||||
@ -88,22 +88,39 @@ static PyObject * PyThing_emitEvent(PyThing* self, PyObject* args)
|
||||
}
|
||||
|
||||
EventTypeId eventTypeId = EventTypeId(eventTypeIdStr);
|
||||
ParamList params;
|
||||
|
||||
// if (valueObj != nullptr) {
|
||||
// PyObject* repr = PyObject_Repr(valueObj);
|
||||
// PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~");
|
||||
// const char *bytes = PyBytes_AS_STRING(str);
|
||||
if (valueObj != nullptr) {
|
||||
PyObject *iter = PyObject_GetIter(valueObj);
|
||||
|
||||
// QVariant value(bytes);
|
||||
// }
|
||||
while (iter) {
|
||||
PyObject *next = PyIter_Next(iter);
|
||||
if (!next) {
|
||||
break;
|
||||
}
|
||||
if (next->ob_type != &PyParamType) {
|
||||
qCWarning(dcThingManager()) << "Invalid parameter passed in param list";
|
||||
continue;
|
||||
}
|
||||
|
||||
PyParam *pyParam = reinterpret_cast<PyParam*>(next);
|
||||
ParamTypeId paramTypeId = ParamTypeId(PyUnicode_AsUTF8(pyParam->pyParamTypeId));
|
||||
|
||||
if (self->ptrObj != nullptr) {
|
||||
QMetaObject::invokeMethod(self->ptrObj, "emitEvent", Qt::QueuedConnection, Q_ARG(EventTypeId, eventTypeId));
|
||||
// Is there a better way to convert a PyObject to a QVariant?
|
||||
PyObject* repr = PyObject_Repr(pyParam->pyValue);
|
||||
PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~");
|
||||
const char *bytes = PyBytes_AS_STRING(str);
|
||||
Py_XDECREF(repr);
|
||||
Py_XDECREF(str);
|
||||
|
||||
QVariant value(bytes);
|
||||
params.append(Param(paramTypeId, value));
|
||||
}
|
||||
}
|
||||
|
||||
// Py_XDECREF(repr);
|
||||
// Py_XDECREF(str);
|
||||
if (self->thing != nullptr) {
|
||||
QMetaObject::invokeMethod(self->thing, "emitEvent", Qt::QueuedConnection, Q_ARG(EventTypeId, eventTypeId), Q_ARG(ParamList, params));
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
@ -153,7 +170,7 @@ static void registerThingType(PyObject *module)
|
||||
PyThingType.tp_doc = "Thing class";
|
||||
PyThingType.tp_methods = PyThing_methods;
|
||||
PyThingType.tp_getset = PyThing_getseters;
|
||||
// PyThingType.tp_members = PyThingSetupInfo_members;
|
||||
// PyThingType.tp_members = PyThingSetupInfo_members;
|
||||
PyThingType.tp_init = reinterpret_cast<initproc>(PyThing_init);
|
||||
|
||||
if (PyType_Ready(&PyThingType) < 0) {
|
||||
|
||||
111
libnymea-core/integrations/python/pythingactioninfo.h
Normal file
111
libnymea-core/integrations/python/pythingactioninfo.h
Normal file
@ -0,0 +1,111 @@
|
||||
#ifndef PYTHINGACTIONINFO_H
|
||||
#define PYTHINGACTIONINFO_H
|
||||
|
||||
#include <Python.h>
|
||||
#include "structmember.h"
|
||||
|
||||
#include "pything.h"
|
||||
|
||||
#include "integrations/thingactioninfo.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
||||
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
ThingActionInfo* info;
|
||||
PyThing *pyThing;
|
||||
PyObject *pyActionTypeId;
|
||||
PyObject *pyParams;
|
||||
} PyThingActionInfo;
|
||||
|
||||
|
||||
static int PyThingActionInfo_init(PyThingActionInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void PyThingActionInfo_dealloc(PyThingActionInfo * self) {
|
||||
// FIXME: Why is this not called? Seems we're leaking...
|
||||
Q_ASSERT(false);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
static PyObject * PyThingActionInfo_finish(PyThingActionInfo* self, PyObject* args) {
|
||||
int status;
|
||||
char *message = nullptr;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i|s", &status, &message)) {
|
||||
PyErr_SetString(PyExc_TypeError, "Invalid arguments in finish call. Expected: finish(ThingError, message = \"\"");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Thing::ThingError thingError = static_cast<Thing::ThingError>(status);
|
||||
QString displayMessage = message != nullptr ? QString(message) : QString();
|
||||
|
||||
if (self->info) {
|
||||
QMetaObject::invokeMethod(self->info, "finish", Qt::QueuedConnection, Q_ARG(Thing::ThingError, thingError), Q_ARG(QString, displayMessage));
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMemberDef PyThingActionInfo_members[] = {
|
||||
{"thing", T_OBJECT_EX, offsetof(PyThingActionInfo, pyThing), 0, "Thing this action is for"},
|
||||
{"actionTypeId", T_OBJECT_EX, offsetof(PyThingActionInfo, pyActionTypeId), 0, "The action type id for this action"},
|
||||
{nullptr, 0, 0, 0, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyMethodDef PyThingActionInfo_methods[] = {
|
||||
{ "finish", (PyCFunction)PyThingActionInfo_finish, METH_VARARGS, "finish an action" },
|
||||
{nullptr, nullptr, 0, nullptr} // sentinel
|
||||
};
|
||||
|
||||
static PyTypeObject PyThingActionInfoType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"nymea.ThingActionInfo", /* tp_name */
|
||||
sizeof(PyThingActionInfo), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
0, /* tp_dealloc */
|
||||
0, /* tp_vectorcall_offset */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_as_async */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
"Noddy objects", /* tp_doc */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
static void registerThingActionInfoType(PyObject *module) {
|
||||
PyThingActionInfoType.tp_new = PyType_GenericNew;
|
||||
PyThingActionInfoType.tp_dealloc=(destructor) PyThingActionInfo_dealloc;
|
||||
PyThingActionInfoType.tp_basicsize = sizeof(PyThingActionInfo);
|
||||
PyThingActionInfoType.tp_flags = Py_TPFLAGS_DEFAULT;
|
||||
PyThingActionInfoType.tp_doc = "ThingActionInfo class";
|
||||
PyThingActionInfoType.tp_methods = PyThingActionInfo_methods;
|
||||
PyThingActionInfoType.tp_members = PyThingActionInfo_members;
|
||||
PyThingActionInfoType.tp_init = (initproc)PyThingActionInfo_init;
|
||||
|
||||
if (PyType_Ready(&PyThingActionInfoType) < 0) {
|
||||
return;
|
||||
}
|
||||
PyModule_AddObject(module, "ThingActionInfo", (PyObject *)&PyThingActionInfoType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#endif // PYTHINGACTIONINFO_H
|
||||
@ -13,10 +13,9 @@
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject* thingClassId;
|
||||
PyObject* name;
|
||||
PyObject* description;
|
||||
ThingDescriptor descriptor;
|
||||
PyObject* pyThingClassId;
|
||||
PyObject* pyName;
|
||||
PyObject* pyDescription;
|
||||
} PyThingDescriptor;
|
||||
|
||||
static PyMethodDef PyThingDescriptor_methods[] = {
|
||||
@ -25,9 +24,9 @@ static PyMethodDef PyThingDescriptor_methods[] = {
|
||||
};
|
||||
|
||||
static PyMemberDef PyThingDescriptor_members[] = {
|
||||
{"thingClassId", T_OBJECT_EX, offsetof(PyThingDescriptor, thingClassId), 0, "Descriptor thingClassId"},
|
||||
{"name", T_OBJECT_EX, offsetof(PyThingDescriptor, name), 0, "Descriptor name"},
|
||||
{"description", T_OBJECT_EX, offsetof(PyThingDescriptor, description), 0, "Descriptor description"},
|
||||
{"thingClassId", T_OBJECT_EX, offsetof(PyThingDescriptor, pyThingClassId), 0, "Descriptor thingClassId"},
|
||||
{"name", T_OBJECT_EX, offsetof(PyThingDescriptor, pyName), 0, "Descriptor name"},
|
||||
{"description", T_OBJECT_EX, offsetof(PyThingDescriptor, pyDescription), 0, "Descriptor description"},
|
||||
{nullptr, 0, 0, 0, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
@ -35,28 +34,25 @@ static PyMemberDef PyThingDescriptor_members[] = {
|
||||
static int PyThingDescriptor_init(PyThingDescriptor *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static char *kwlist[] = {"thingClassId", "name", "description", nullptr};
|
||||
PyObject *thingClassId = nullptr, *name = nullptr, *description = nullptr, *tmp = nullptr;
|
||||
PyObject *thingClassId = nullptr, *name = nullptr, *description = nullptr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO", kwlist, &thingClassId, &name, &description))
|
||||
return -1;
|
||||
|
||||
if (thingClassId) {
|
||||
tmp = self->thingClassId;
|
||||
Py_XDECREF(self->pyThingClassId);
|
||||
Py_INCREF(thingClassId);
|
||||
self->thingClassId = thingClassId;
|
||||
Py_XDECREF(tmp);
|
||||
self->pyThingClassId = thingClassId;
|
||||
}
|
||||
if (name) {
|
||||
tmp = self->name;
|
||||
Py_XDECREF(self->pyName);
|
||||
Py_INCREF(name);
|
||||
self->name = name;
|
||||
Py_XDECREF(tmp);
|
||||
self->pyName = name;
|
||||
}
|
||||
if (description) {
|
||||
tmp = self->description;
|
||||
Py_XDECREF(self->pyDescription);
|
||||
Py_INCREF(description);
|
||||
self->description = description;
|
||||
Py_XDECREF(tmp);
|
||||
self->pyDescription = description;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -19,20 +19,16 @@
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
ThingDiscoveryInfo* ptrObj;
|
||||
ThingDiscoveryInfo* info;
|
||||
} PyThingDiscoveryInfo;
|
||||
|
||||
|
||||
static int PyThingDiscoveryInfo_init(PyThingDiscoveryInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/)
|
||||
// initialize PyVoice Object
|
||||
{
|
||||
static int PyThingDiscoveryInfo_init(PyThingDiscoveryInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void PyThingDiscoveryInfo_dealloc(PyThingDiscoveryInfo * self)
|
||||
// destruct the object
|
||||
{
|
||||
static void PyThingDiscoveryInfo_dealloc(PyThingDiscoveryInfo * self) {
|
||||
// FIXME: Why is this not called? Seems we're leaking...
|
||||
Q_ASSERT(false);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
@ -41,20 +37,20 @@ static void PyThingDiscoveryInfo_dealloc(PyThingDiscoveryInfo * self)
|
||||
static PyObject * PyThingDiscoveryInfo_finish(PyThingDiscoveryInfo* self, PyObject* args)
|
||||
{
|
||||
int status;
|
||||
char *message;
|
||||
char *message = nullptr;
|
||||
|
||||
if (PyArg_ParseTuple(args, "is", &status, &message)) {
|
||||
(self->ptrObj)->finish(static_cast<Thing::ThingError>(status), QString(message));
|
||||
Py_RETURN_NONE;
|
||||
if (!PyArg_ParseTuple(args, "i|s", &status, &message)) {
|
||||
PyErr_SetString(PyExc_TypeError, "Invalid arguments in finish call. Expected: finish(ThingError, message = \"\"");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (PyArg_ParseTuple(args, "i", &status)) {
|
||||
(self->ptrObj)->finish(static_cast<Thing::ThingError>(status));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
Thing::ThingError thingError = static_cast<Thing::ThingError>(status);
|
||||
QString displayMessage = message != nullptr ? QString(message) : QString();
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "Invalid arguments in finish call. Expected: finish(ThingError, message = \"\"");
|
||||
return nullptr;
|
||||
if (self->info) {
|
||||
QMetaObject::invokeMethod(self->info, "finish", Qt::QueuedConnection, Q_ARG(Thing::ThingError, thingError), Q_ARG(QString, displayMessage));
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject * PyThingDiscoveryInfo_addDescriptor(PyThingDiscoveryInfo* self, PyObject* args) {
|
||||
@ -72,21 +68,23 @@ static PyObject * PyThingDiscoveryInfo_addDescriptor(PyThingDiscoveryInfo* self,
|
||||
PyThingDescriptor *pyDescriptor = (PyThingDescriptor*)pyObj;
|
||||
|
||||
ThingClassId thingClassId;
|
||||
if (pyDescriptor->thingClassId) {
|
||||
thingClassId = ThingClassId(PyUnicode_AsUTF8(pyDescriptor->thingClassId));
|
||||
if (pyDescriptor->pyThingClassId) {
|
||||
thingClassId = ThingClassId(PyUnicode_AsUTF8(pyDescriptor->pyThingClassId));
|
||||
}
|
||||
QString name;
|
||||
if (pyDescriptor->name) {
|
||||
name = QString::fromUtf8(PyUnicode_AsUTF8(pyDescriptor->name));
|
||||
if (pyDescriptor->pyName) {
|
||||
name = QString::fromUtf8(PyUnicode_AsUTF8(pyDescriptor->pyName));
|
||||
}
|
||||
QString description;
|
||||
if (pyDescriptor->description) {
|
||||
description = QString::fromUtf8(PyUnicode_AsUTF8(pyDescriptor->description));
|
||||
if (pyDescriptor->pyDescription) {
|
||||
description = QString::fromUtf8(PyUnicode_AsUTF8(pyDescriptor->pyDescription));
|
||||
}
|
||||
|
||||
ThingDescriptor descriptor(thingClassId, name, description);
|
||||
|
||||
self->ptrObj->addThingDescriptor(descriptor);
|
||||
if (self->info) {
|
||||
QMetaObject::invokeMethod(self->info, "addThingDescriptor", Qt::QueuedConnection, Q_ARG(ThingDescriptor, descriptor));
|
||||
}
|
||||
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
@ -14,45 +14,41 @@
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
ThingSetupInfo* ptrObj;
|
||||
PyThing *thing;
|
||||
ThingSetupInfo* info;
|
||||
PyThing *pyThing;
|
||||
} PyThingSetupInfo;
|
||||
|
||||
|
||||
static int PyThingSetupInfo_init(PyThingSetupInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/)
|
||||
{
|
||||
static int PyThingSetupInfo_init(PyThingSetupInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void PyThingSetupInfo_dealloc(PyThingSetupInfo * self)
|
||||
{
|
||||
// FIXME: Why is this not called? Seems we're leaking...
|
||||
Q_ASSERT(false);
|
||||
static void PyThingSetupInfo_dealloc(PyThingSetupInfo * self) {
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
static PyObject * PyThingSetupInfo_finish(PyThingSetupInfo* self, PyObject* args)
|
||||
{
|
||||
static PyObject * PyThingSetupInfo_finish(PyThingSetupInfo* self, PyObject* args) {
|
||||
int status;
|
||||
char *message;
|
||||
char *message = nullptr;
|
||||
|
||||
if (PyArg_ParseTuple(args, "is", &status, &message)) {
|
||||
(self->ptrObj)->finish(static_cast<Thing::ThingError>(status), QString(message));
|
||||
Py_RETURN_NONE;
|
||||
if (!PyArg_ParseTuple(args, "i|s", &status, &message)) {
|
||||
PyErr_SetString(PyExc_TypeError, "Invalid arguments in finish call. Expected: finish(ThingError, message = \"\"");
|
||||
return nullptr;
|
||||
}
|
||||
PyErr_Clear();
|
||||
|
||||
if (PyArg_ParseTuple(args, "i", &status)) {
|
||||
(self->ptrObj)->finish(static_cast<Thing::ThingError>(status));
|
||||
Py_RETURN_NONE;
|
||||
Thing::ThingError thingError = static_cast<Thing::ThingError>(status);
|
||||
QString displayMessage = message != nullptr ? QString(message) : QString();
|
||||
|
||||
if (self->info) {
|
||||
QMetaObject::invokeMethod(self->info, "finish", Qt::QueuedConnection, Q_ARG(Thing::ThingError, thingError), Q_ARG(QString, displayMessage));
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMemberDef PyThingSetupInfo_members[] = {
|
||||
{"thing", T_OBJECT_EX, offsetof(PyThingSetupInfo, thing), 0, "Thing being setup in this setup transaction"},
|
||||
{"thing", T_OBJECT_EX, offsetof(PyThingSetupInfo, pyThing), 0, "Thing being setup in this setup transaction"},
|
||||
{nullptr, 0, 0, 0, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
#include "python/pything.h"
|
||||
#include "python/pythingdiscoveryinfo.h"
|
||||
#include "python/pythingsetupinfo.h"
|
||||
#include "python/pyparam.h"
|
||||
#include "python/pythingactioninfo.h"
|
||||
|
||||
#include "pythonintegrationplugin.h"
|
||||
|
||||
@ -14,15 +16,11 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QtConcurrent/QtConcurrentRun>
|
||||
|
||||
QHash<PyObject*, PyThreadState*> s_modules;
|
||||
PyThreadState* PythonIntegrationPlugin::s_mainThread = nullptr;
|
||||
PyObject* PythonIntegrationPlugin::s_nymeaModule = nullptr;
|
||||
PyObject* PythonIntegrationPlugin::s_asyncio = nullptr;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Write to stdout/stderr
|
||||
PyObject* nymea_write(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
@ -98,10 +96,12 @@ PyMODINIT_FUNC PyInit_nymea(void)
|
||||
|
||||
|
||||
registerNymeaLoggingHandler(m);
|
||||
registerParamType(m);
|
||||
registerThingType(m);
|
||||
registerThingDescriptorType(m);
|
||||
registerThingDiscoveryInfoType(m);
|
||||
registerThingSetupInfoType(m);
|
||||
registerThingActionInfoType(m);
|
||||
|
||||
return m;
|
||||
}
|
||||
@ -192,11 +192,11 @@ void PythonIntegrationPlugin::init()
|
||||
void PythonIntegrationPlugin::discoverThings(ThingDiscoveryInfo *info)
|
||||
{
|
||||
PyThingDiscoveryInfo *pyInfo = PyObject_New(PyThingDiscoveryInfo, &PyThingDiscoveryInfoType);
|
||||
pyInfo->ptrObj = info;
|
||||
pyInfo->info = info;
|
||||
|
||||
connect(info, &ThingDiscoveryInfo::destroyed, this, [=](){
|
||||
PyGILState_STATE s = PyGILState_Ensure();
|
||||
pyInfo->ptrObj = nullptr;
|
||||
pyInfo->info = nullptr;
|
||||
PyObject_Del(pyInfo);
|
||||
PyGILState_Release(s);
|
||||
});
|
||||
@ -207,11 +207,11 @@ void PythonIntegrationPlugin::discoverThings(ThingDiscoveryInfo *info)
|
||||
void PythonIntegrationPlugin::setupThing(ThingSetupInfo *info)
|
||||
{
|
||||
PyThing *pyThing = PyObject_New(PyThing, &PyThingType);
|
||||
pyThing->ptrObj = info->thing();
|
||||
pyThing->thing = info->thing();
|
||||
|
||||
PyThingSetupInfo *pyInfo = PyObject_New(PyThingSetupInfo, &PyThingSetupInfoType);
|
||||
pyInfo->ptrObj = info;
|
||||
pyInfo->thing = pyThing;
|
||||
pyInfo->info = info;
|
||||
pyInfo->pyThing = pyThing;
|
||||
|
||||
|
||||
connect(info, &ThingSetupInfo::finished, this, [=](){
|
||||
@ -230,7 +230,8 @@ void PythonIntegrationPlugin::setupThing(ThingSetupInfo *info)
|
||||
});
|
||||
connect(info, &ThingSetupInfo::destroyed, this, [=](){
|
||||
PyGILState_STATE s = PyGILState_Ensure();
|
||||
PyObject_Del(pyInfo);
|
||||
pyInfo->info = nullptr;
|
||||
Py_DECREF(pyInfo);
|
||||
PyGILState_Release(s);
|
||||
});
|
||||
|
||||
@ -244,6 +245,32 @@ void PythonIntegrationPlugin::postSetupThing(Thing *thing)
|
||||
callPluginFunction("postSetupThing", reinterpret_cast<PyObject*>(pyThing));
|
||||
}
|
||||
|
||||
void PythonIntegrationPlugin::executeAction(ThingActionInfo *info)
|
||||
{
|
||||
PyThing *pyThing = m_things.value(info->thing());
|
||||
|
||||
PyGILState_STATE s = PyGILState_Ensure();
|
||||
|
||||
PyThingActionInfo *pyInfo = PyObject_New(PyThingActionInfo, &PyThingActionInfoType);
|
||||
pyInfo->info = info;
|
||||
pyInfo->pyThing = pyThing;
|
||||
pyInfo->pyActionTypeId = PyUnicode_FromString(info->action().actionTypeId().toString().toUtf8());
|
||||
pyInfo->pyParams = PyParam_FromParamList(info->action().params());
|
||||
|
||||
PyGILState_Release(s);
|
||||
|
||||
connect(info, &ThingActionInfo::destroyed, this, [=](){
|
||||
PyGILState_STATE s = PyGILState_Ensure();
|
||||
pyInfo->pyActionTypeId = nullptr;
|
||||
Py_DECREF(pyInfo->pyActionTypeId);
|
||||
pyInfo->info = nullptr;
|
||||
Py_DECREF(pyInfo);
|
||||
PyGILState_Release(s);
|
||||
});
|
||||
|
||||
callPluginFunction("executeAction", reinterpret_cast<PyObject*>(pyInfo));
|
||||
}
|
||||
|
||||
void PythonIntegrationPlugin::thingRemoved(Thing *thing)
|
||||
{
|
||||
PyThing *pyThing = m_things.value(thing);
|
||||
@ -252,10 +279,9 @@ void PythonIntegrationPlugin::thingRemoved(Thing *thing)
|
||||
|
||||
PyGILState_STATE s = PyGILState_Ensure();
|
||||
|
||||
pyThing->ptrObj = nullptr;
|
||||
pyThing->thing = nullptr;
|
||||
Py_DECREF(pyThing);
|
||||
|
||||
|
||||
PyGILState_Release(s);
|
||||
|
||||
m_things.remove(thing);
|
||||
|
||||
@ -29,6 +29,7 @@ public:
|
||||
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||
void setupThing(ThingSetupInfo *info) override;
|
||||
void postSetupThing(Thing *thing) override;
|
||||
void executeAction(ThingActionInfo *info) override;
|
||||
void thingRemoved(Thing *thing) override;
|
||||
|
||||
|
||||
|
||||
@ -21,7 +21,9 @@ RESOURCES += $$top_srcdir/icons.qrc \
|
||||
HEADERS += nymeacore.h \
|
||||
integrations/plugininfocache.h \
|
||||
integrations/python/pynymealogginghandler.h \
|
||||
integrations/python/pyparam.h \
|
||||
integrations/python/pything.h \
|
||||
integrations/python/pythingactioninfo.h \
|
||||
integrations/python/pythingdescriptor.h \
|
||||
integrations/python/pythingdiscoveryinfo.h \
|
||||
integrations/python/pythingsetupinfo.h \
|
||||
|
||||
Reference in New Issue
Block a user