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 <Python.h>
|
||||||
#include "structmember.h"
|
#include "structmember.h"
|
||||||
|
|
||||||
|
#include "pyparam.h"
|
||||||
|
|
||||||
#include "integrations/thing.h"
|
#include "integrations/thing.h"
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
@ -15,7 +17,7 @@
|
|||||||
|
|
||||||
typedef struct _thing {
|
typedef struct _thing {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
Thing *ptrObj;
|
Thing *thing;
|
||||||
} PyThing;
|
} PyThing;
|
||||||
|
|
||||||
|
|
||||||
@ -25,26 +27,24 @@ static int PyThing_init(PyThing */*self*/, PyObject */*args*/, PyObject */*kwds*
|
|||||||
|
|
||||||
|
|
||||||
static void PyThing_dealloc(PyThing * self) {
|
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);
|
Py_TYPE(self)->tp_free(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *PyThing_getName(PyThing *self, void */*closure*/)
|
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.");
|
PyErr_SetString(PyExc_ValueError, "Thing has been removed from the system.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// FIXME: Needs blocking queued connection
|
// 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);
|
Py_INCREF(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PyThing_setName(PyThing *self, PyObject *value, void */*closure*/){
|
static int PyThing_setName(PyThing *self, PyObject *value, void */*closure*/){
|
||||||
// FIXME: Needs queued connection
|
// FIXME: Needs queued connection
|
||||||
self->ptrObj->setName(QString(PyUnicode_AsUTF8(value)));
|
self->thing->setName(QString(PyUnicode_AsUTF8(value)));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,8 +67,8 @@ static PyObject * PyThing_setStateValue(PyThing* self, PyObject* args)
|
|||||||
|
|
||||||
QVariant value(bytes);
|
QVariant value(bytes);
|
||||||
|
|
||||||
if (self->ptrObj != nullptr) {
|
if (self->thing != nullptr) {
|
||||||
QMetaObject::invokeMethod(self->ptrObj, "setStateValue", Qt::QueuedConnection, Q_ARG(StateTypeId, stateTypeId), Q_ARG(QVariant, value));
|
QMetaObject::invokeMethod(self->thing, "setStateValue", Qt::QueuedConnection, Q_ARG(StateTypeId, stateTypeId), Q_ARG(QVariant, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_XDECREF(repr);
|
Py_XDECREF(repr);
|
||||||
@ -88,22 +88,39 @@ static PyObject * PyThing_emitEvent(PyThing* self, PyObject* args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
EventTypeId eventTypeId = EventTypeId(eventTypeIdStr);
|
EventTypeId eventTypeId = EventTypeId(eventTypeIdStr);
|
||||||
|
ParamList params;
|
||||||
|
|
||||||
// if (valueObj != nullptr) {
|
if (valueObj != nullptr) {
|
||||||
// PyObject* repr = PyObject_Repr(valueObj);
|
PyObject *iter = PyObject_GetIter(valueObj);
|
||||||
// PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~");
|
|
||||||
// const char *bytes = PyBytes_AS_STRING(str);
|
|
||||||
|
|
||||||
// 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) {
|
// Is there a better way to convert a PyObject to a QVariant?
|
||||||
QMetaObject::invokeMethod(self->ptrObj, "emitEvent", Qt::QueuedConnection, Q_ARG(EventTypeId, eventTypeId));
|
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);
|
if (self->thing != nullptr) {
|
||||||
// Py_XDECREF(str);
|
QMetaObject::invokeMethod(self->thing, "emitEvent", Qt::QueuedConnection, Q_ARG(EventTypeId, eventTypeId), Q_ARG(ParamList, params));
|
||||||
|
}
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
@ -153,7 +170,7 @@ static void registerThingType(PyObject *module)
|
|||||||
PyThingType.tp_doc = "Thing class";
|
PyThingType.tp_doc = "Thing class";
|
||||||
PyThingType.tp_methods = PyThing_methods;
|
PyThingType.tp_methods = PyThing_methods;
|
||||||
PyThingType.tp_getset = PyThing_getseters;
|
PyThingType.tp_getset = PyThing_getseters;
|
||||||
// PyThingType.tp_members = PyThingSetupInfo_members;
|
// PyThingType.tp_members = PyThingSetupInfo_members;
|
||||||
PyThingType.tp_init = reinterpret_cast<initproc>(PyThing_init);
|
PyThingType.tp_init = reinterpret_cast<initproc>(PyThing_init);
|
||||||
|
|
||||||
if (PyType_Ready(&PyThingType) < 0) {
|
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 {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
PyObject* thingClassId;
|
PyObject* pyThingClassId;
|
||||||
PyObject* name;
|
PyObject* pyName;
|
||||||
PyObject* description;
|
PyObject* pyDescription;
|
||||||
ThingDescriptor descriptor;
|
|
||||||
} PyThingDescriptor;
|
} PyThingDescriptor;
|
||||||
|
|
||||||
static PyMethodDef PyThingDescriptor_methods[] = {
|
static PyMethodDef PyThingDescriptor_methods[] = {
|
||||||
@ -25,9 +24,9 @@ static PyMethodDef PyThingDescriptor_methods[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static PyMemberDef PyThingDescriptor_members[] = {
|
static PyMemberDef PyThingDescriptor_members[] = {
|
||||||
{"thingClassId", T_OBJECT_EX, offsetof(PyThingDescriptor, thingClassId), 0, "Descriptor thingClassId"},
|
{"thingClassId", T_OBJECT_EX, offsetof(PyThingDescriptor, pyThingClassId), 0, "Descriptor thingClassId"},
|
||||||
{"name", T_OBJECT_EX, offsetof(PyThingDescriptor, name), 0, "Descriptor name"},
|
{"name", T_OBJECT_EX, offsetof(PyThingDescriptor, pyName), 0, "Descriptor name"},
|
||||||
{"description", T_OBJECT_EX, offsetof(PyThingDescriptor, description), 0, "Descriptor description"},
|
{"description", T_OBJECT_EX, offsetof(PyThingDescriptor, pyDescription), 0, "Descriptor description"},
|
||||||
{nullptr, 0, 0, 0, nullptr} /* Sentinel */
|
{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 int PyThingDescriptor_init(PyThingDescriptor *self, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
static char *kwlist[] = {"thingClassId", "name", "description", nullptr};
|
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))
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO", kwlist, &thingClassId, &name, &description))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (thingClassId) {
|
if (thingClassId) {
|
||||||
tmp = self->thingClassId;
|
Py_XDECREF(self->pyThingClassId);
|
||||||
Py_INCREF(thingClassId);
|
Py_INCREF(thingClassId);
|
||||||
self->thingClassId = thingClassId;
|
self->pyThingClassId = thingClassId;
|
||||||
Py_XDECREF(tmp);
|
|
||||||
}
|
}
|
||||||
if (name) {
|
if (name) {
|
||||||
tmp = self->name;
|
Py_XDECREF(self->pyName);
|
||||||
Py_INCREF(name);
|
Py_INCREF(name);
|
||||||
self->name = name;
|
self->pyName = name;
|
||||||
Py_XDECREF(tmp);
|
|
||||||
}
|
}
|
||||||
if (description) {
|
if (description) {
|
||||||
tmp = self->description;
|
Py_XDECREF(self->pyDescription);
|
||||||
Py_INCREF(description);
|
Py_INCREF(description);
|
||||||
self->description = description;
|
self->pyDescription = description;
|
||||||
Py_XDECREF(tmp);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,20 +19,16 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
ThingDiscoveryInfo* ptrObj;
|
ThingDiscoveryInfo* info;
|
||||||
} PyThingDiscoveryInfo;
|
} PyThingDiscoveryInfo;
|
||||||
|
|
||||||
|
|
||||||
static int PyThingDiscoveryInfo_init(PyThingDiscoveryInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/)
|
static int PyThingDiscoveryInfo_init(PyThingDiscoveryInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/) {
|
||||||
// initialize PyVoice Object
|
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void PyThingDiscoveryInfo_dealloc(PyThingDiscoveryInfo * self)
|
static void PyThingDiscoveryInfo_dealloc(PyThingDiscoveryInfo * self) {
|
||||||
// destruct the object
|
|
||||||
{
|
|
||||||
// FIXME: Why is this not called? Seems we're leaking...
|
// FIXME: Why is this not called? Seems we're leaking...
|
||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
Py_TYPE(self)->tp_free(self);
|
Py_TYPE(self)->tp_free(self);
|
||||||
@ -41,20 +37,20 @@ static void PyThingDiscoveryInfo_dealloc(PyThingDiscoveryInfo * self)
|
|||||||
static PyObject * PyThingDiscoveryInfo_finish(PyThingDiscoveryInfo* self, PyObject* args)
|
static PyObject * PyThingDiscoveryInfo_finish(PyThingDiscoveryInfo* self, PyObject* args)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
char *message;
|
char *message = nullptr;
|
||||||
|
|
||||||
if (PyArg_ParseTuple(args, "is", &status, &message)) {
|
if (!PyArg_ParseTuple(args, "i|s", &status, &message)) {
|
||||||
(self->ptrObj)->finish(static_cast<Thing::ThingError>(status), QString(message));
|
PyErr_SetString(PyExc_TypeError, "Invalid arguments in finish call. Expected: finish(ThingError, message = \"\"");
|
||||||
Py_RETURN_NONE;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyArg_ParseTuple(args, "i", &status)) {
|
Thing::ThingError thingError = static_cast<Thing::ThingError>(status);
|
||||||
(self->ptrObj)->finish(static_cast<Thing::ThingError>(status));
|
QString displayMessage = message != nullptr ? QString(message) : QString();
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyErr_SetString(PyExc_TypeError, "Invalid arguments in finish call. Expected: finish(ThingError, message = \"\"");
|
if (self->info) {
|
||||||
return nullptr;
|
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) {
|
static PyObject * PyThingDiscoveryInfo_addDescriptor(PyThingDiscoveryInfo* self, PyObject* args) {
|
||||||
@ -72,21 +68,23 @@ static PyObject * PyThingDiscoveryInfo_addDescriptor(PyThingDiscoveryInfo* self,
|
|||||||
PyThingDescriptor *pyDescriptor = (PyThingDescriptor*)pyObj;
|
PyThingDescriptor *pyDescriptor = (PyThingDescriptor*)pyObj;
|
||||||
|
|
||||||
ThingClassId thingClassId;
|
ThingClassId thingClassId;
|
||||||
if (pyDescriptor->thingClassId) {
|
if (pyDescriptor->pyThingClassId) {
|
||||||
thingClassId = ThingClassId(PyUnicode_AsUTF8(pyDescriptor->thingClassId));
|
thingClassId = ThingClassId(PyUnicode_AsUTF8(pyDescriptor->pyThingClassId));
|
||||||
}
|
}
|
||||||
QString name;
|
QString name;
|
||||||
if (pyDescriptor->name) {
|
if (pyDescriptor->pyName) {
|
||||||
name = QString::fromUtf8(PyUnicode_AsUTF8(pyDescriptor->name));
|
name = QString::fromUtf8(PyUnicode_AsUTF8(pyDescriptor->pyName));
|
||||||
}
|
}
|
||||||
QString description;
|
QString description;
|
||||||
if (pyDescriptor->description) {
|
if (pyDescriptor->pyDescription) {
|
||||||
description = QString::fromUtf8(PyUnicode_AsUTF8(pyDescriptor->description));
|
description = QString::fromUtf8(PyUnicode_AsUTF8(pyDescriptor->pyDescription));
|
||||||
}
|
}
|
||||||
|
|
||||||
ThingDescriptor descriptor(thingClassId, name, description);
|
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("");
|
return Py_BuildValue("");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,45 +14,41 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
ThingSetupInfo* ptrObj;
|
ThingSetupInfo* info;
|
||||||
PyThing *thing;
|
PyThing *pyThing;
|
||||||
} PyThingSetupInfo;
|
} PyThingSetupInfo;
|
||||||
|
|
||||||
|
|
||||||
static int PyThingSetupInfo_init(PyThingSetupInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/)
|
static int PyThingSetupInfo_init(PyThingSetupInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void PyThingSetupInfo_dealloc(PyThingSetupInfo * self)
|
static void PyThingSetupInfo_dealloc(PyThingSetupInfo * self) {
|
||||||
{
|
|
||||||
// FIXME: Why is this not called? Seems we're leaking...
|
|
||||||
Q_ASSERT(false);
|
|
||||||
Py_TYPE(self)->tp_free(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;
|
int status;
|
||||||
char *message;
|
char *message = nullptr;
|
||||||
|
|
||||||
if (PyArg_ParseTuple(args, "is", &status, &message)) {
|
if (!PyArg_ParseTuple(args, "i|s", &status, &message)) {
|
||||||
(self->ptrObj)->finish(static_cast<Thing::ThingError>(status), QString(message));
|
PyErr_SetString(PyExc_TypeError, "Invalid arguments in finish call. Expected: finish(ThingError, message = \"\"");
|
||||||
Py_RETURN_NONE;
|
return nullptr;
|
||||||
}
|
}
|
||||||
PyErr_Clear();
|
|
||||||
|
|
||||||
if (PyArg_ParseTuple(args, "i", &status)) {
|
Thing::ThingError thingError = static_cast<Thing::ThingError>(status);
|
||||||
(self->ptrObj)->finish(static_cast<Thing::ThingError>(status));
|
QString displayMessage = message != nullptr ? QString(message) : QString();
|
||||||
Py_RETURN_NONE;
|
|
||||||
|
if (self->info) {
|
||||||
|
QMetaObject::invokeMethod(self->info, "finish", Qt::QueuedConnection, Q_ARG(Thing::ThingError, thingError), Q_ARG(QString, displayMessage));
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMemberDef PyThingSetupInfo_members[] = {
|
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 */
|
{nullptr, 0, 0, 0, nullptr} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
#include "python/pything.h"
|
#include "python/pything.h"
|
||||||
#include "python/pythingdiscoveryinfo.h"
|
#include "python/pythingdiscoveryinfo.h"
|
||||||
#include "python/pythingsetupinfo.h"
|
#include "python/pythingsetupinfo.h"
|
||||||
|
#include "python/pyparam.h"
|
||||||
|
#include "python/pythingactioninfo.h"
|
||||||
|
|
||||||
#include "pythonintegrationplugin.h"
|
#include "pythonintegrationplugin.h"
|
||||||
|
|
||||||
@ -14,15 +16,11 @@
|
|||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
|
||||||
QHash<PyObject*, PyThreadState*> s_modules;
|
|
||||||
PyThreadState* PythonIntegrationPlugin::s_mainThread = nullptr;
|
PyThreadState* PythonIntegrationPlugin::s_mainThread = nullptr;
|
||||||
PyObject* PythonIntegrationPlugin::s_nymeaModule = nullptr;
|
PyObject* PythonIntegrationPlugin::s_nymeaModule = nullptr;
|
||||||
PyObject* PythonIntegrationPlugin::s_asyncio = nullptr;
|
PyObject* PythonIntegrationPlugin::s_asyncio = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Write to stdout/stderr
|
// Write to stdout/stderr
|
||||||
PyObject* nymea_write(PyObject* /*self*/, PyObject* args)
|
PyObject* nymea_write(PyObject* /*self*/, PyObject* args)
|
||||||
{
|
{
|
||||||
@ -98,10 +96,12 @@ PyMODINIT_FUNC PyInit_nymea(void)
|
|||||||
|
|
||||||
|
|
||||||
registerNymeaLoggingHandler(m);
|
registerNymeaLoggingHandler(m);
|
||||||
|
registerParamType(m);
|
||||||
registerThingType(m);
|
registerThingType(m);
|
||||||
registerThingDescriptorType(m);
|
registerThingDescriptorType(m);
|
||||||
registerThingDiscoveryInfoType(m);
|
registerThingDiscoveryInfoType(m);
|
||||||
registerThingSetupInfoType(m);
|
registerThingSetupInfoType(m);
|
||||||
|
registerThingActionInfoType(m);
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
@ -192,11 +192,11 @@ void PythonIntegrationPlugin::init()
|
|||||||
void PythonIntegrationPlugin::discoverThings(ThingDiscoveryInfo *info)
|
void PythonIntegrationPlugin::discoverThings(ThingDiscoveryInfo *info)
|
||||||
{
|
{
|
||||||
PyThingDiscoveryInfo *pyInfo = PyObject_New(PyThingDiscoveryInfo, &PyThingDiscoveryInfoType);
|
PyThingDiscoveryInfo *pyInfo = PyObject_New(PyThingDiscoveryInfo, &PyThingDiscoveryInfoType);
|
||||||
pyInfo->ptrObj = info;
|
pyInfo->info = info;
|
||||||
|
|
||||||
connect(info, &ThingDiscoveryInfo::destroyed, this, [=](){
|
connect(info, &ThingDiscoveryInfo::destroyed, this, [=](){
|
||||||
PyGILState_STATE s = PyGILState_Ensure();
|
PyGILState_STATE s = PyGILState_Ensure();
|
||||||
pyInfo->ptrObj = nullptr;
|
pyInfo->info = nullptr;
|
||||||
PyObject_Del(pyInfo);
|
PyObject_Del(pyInfo);
|
||||||
PyGILState_Release(s);
|
PyGILState_Release(s);
|
||||||
});
|
});
|
||||||
@ -207,11 +207,11 @@ void PythonIntegrationPlugin::discoverThings(ThingDiscoveryInfo *info)
|
|||||||
void PythonIntegrationPlugin::setupThing(ThingSetupInfo *info)
|
void PythonIntegrationPlugin::setupThing(ThingSetupInfo *info)
|
||||||
{
|
{
|
||||||
PyThing *pyThing = PyObject_New(PyThing, &PyThingType);
|
PyThing *pyThing = PyObject_New(PyThing, &PyThingType);
|
||||||
pyThing->ptrObj = info->thing();
|
pyThing->thing = info->thing();
|
||||||
|
|
||||||
PyThingSetupInfo *pyInfo = PyObject_New(PyThingSetupInfo, &PyThingSetupInfoType);
|
PyThingSetupInfo *pyInfo = PyObject_New(PyThingSetupInfo, &PyThingSetupInfoType);
|
||||||
pyInfo->ptrObj = info;
|
pyInfo->info = info;
|
||||||
pyInfo->thing = pyThing;
|
pyInfo->pyThing = pyThing;
|
||||||
|
|
||||||
|
|
||||||
connect(info, &ThingSetupInfo::finished, this, [=](){
|
connect(info, &ThingSetupInfo::finished, this, [=](){
|
||||||
@ -230,7 +230,8 @@ void PythonIntegrationPlugin::setupThing(ThingSetupInfo *info)
|
|||||||
});
|
});
|
||||||
connect(info, &ThingSetupInfo::destroyed, this, [=](){
|
connect(info, &ThingSetupInfo::destroyed, this, [=](){
|
||||||
PyGILState_STATE s = PyGILState_Ensure();
|
PyGILState_STATE s = PyGILState_Ensure();
|
||||||
PyObject_Del(pyInfo);
|
pyInfo->info = nullptr;
|
||||||
|
Py_DECREF(pyInfo);
|
||||||
PyGILState_Release(s);
|
PyGILState_Release(s);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -244,6 +245,32 @@ void PythonIntegrationPlugin::postSetupThing(Thing *thing)
|
|||||||
callPluginFunction("postSetupThing", reinterpret_cast<PyObject*>(pyThing));
|
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)
|
void PythonIntegrationPlugin::thingRemoved(Thing *thing)
|
||||||
{
|
{
|
||||||
PyThing *pyThing = m_things.value(thing);
|
PyThing *pyThing = m_things.value(thing);
|
||||||
@ -252,10 +279,9 @@ void PythonIntegrationPlugin::thingRemoved(Thing *thing)
|
|||||||
|
|
||||||
PyGILState_STATE s = PyGILState_Ensure();
|
PyGILState_STATE s = PyGILState_Ensure();
|
||||||
|
|
||||||
pyThing->ptrObj = nullptr;
|
pyThing->thing = nullptr;
|
||||||
Py_DECREF(pyThing);
|
Py_DECREF(pyThing);
|
||||||
|
|
||||||
|
|
||||||
PyGILState_Release(s);
|
PyGILState_Release(s);
|
||||||
|
|
||||||
m_things.remove(thing);
|
m_things.remove(thing);
|
||||||
|
|||||||
@ -29,6 +29,7 @@ public:
|
|||||||
void discoverThings(ThingDiscoveryInfo *info) override;
|
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||||
void setupThing(ThingSetupInfo *info) override;
|
void setupThing(ThingSetupInfo *info) override;
|
||||||
void postSetupThing(Thing *thing) override;
|
void postSetupThing(Thing *thing) override;
|
||||||
|
void executeAction(ThingActionInfo *info) override;
|
||||||
void thingRemoved(Thing *thing) override;
|
void thingRemoved(Thing *thing) override;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,9 @@ RESOURCES += $$top_srcdir/icons.qrc \
|
|||||||
HEADERS += nymeacore.h \
|
HEADERS += nymeacore.h \
|
||||||
integrations/plugininfocache.h \
|
integrations/plugininfocache.h \
|
||||||
integrations/python/pynymealogginghandler.h \
|
integrations/python/pynymealogginghandler.h \
|
||||||
|
integrations/python/pyparam.h \
|
||||||
integrations/python/pything.h \
|
integrations/python/pything.h \
|
||||||
|
integrations/python/pythingactioninfo.h \
|
||||||
integrations/python/pythingdescriptor.h \
|
integrations/python/pythingdescriptor.h \
|
||||||
integrations/python/pythingdiscoveryinfo.h \
|
integrations/python/pythingdiscoveryinfo.h \
|
||||||
integrations/python/pythingsetupinfo.h \
|
integrations/python/pythingsetupinfo.h \
|
||||||
|
|||||||
Reference in New Issue
Block a user