From: Dongju Chae Date: Thu, 11 Apr 2019 08:27:58 +0000 (+0900) Subject: [PythonFilter/API] Add a python module to provide NNS-related APIs X-Git-Tag: accepted/tizen/unified/20190425.014439~28 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=167952dcf65b24e7473229ec8d6f094c9ccedadf;p=platform%2Fupstream%2Fnnstreamer.git [PythonFilter/API] Add a python module to provide NNS-related APIs It's a python module which a user will import in a python script. Currently, only 'TensorShape' type object is supported. I am currently considering other useful APIs. Signed-off-by: Dongju Chae --- diff --git a/ext/nnstreamer/tensor_filter/tensor_filter_python_api.c b/ext/nnstreamer/tensor_filter/tensor_filter_python_api.c new file mode 100644 index 0000000..d2826a1 --- /dev/null +++ b/ext/nnstreamer/tensor_filter/tensor_filter_python_api.c @@ -0,0 +1,218 @@ +/** + * GStreamer Tensor_Filter, Python Module + * Copyright (C) 2019 Dongju Chae + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + */ +/** + * @file tensor_filter_python_api.c + * @date 10 Apr 2019 + * @brief python helper structure for nnstreamer tensor_filter + * @see http://github.com/nnsuite/nnstreamer + * @author Dongju Chae + * @bug No known bugs except for NYI items + */ + +#include "tensor_filter_python_core.h" + +/** @brief object structure for custom Python type: TensorShape */ +typedef struct { + PyObject_HEAD + PyObject *dims; + PyArray_Descr* type; +} TensorShapeObject; + +/** + * @brief method impl. for setDims + * @param self : Python type object + * @param args : arguments for the method + */ +static PyObject * +TensorShape_setDims(TensorShapeObject *self, PyObject *args) { + PyObject *dims = args; + PyObject *new_dims; + + /** PyArg_ParseTuple() returns borrowed references */ + if (!PyArg_ParseTuple(args, "O", &dims)) + Py_RETURN_NONE; + + if (PyList_Size(dims) < NNS_TENSOR_RANK_LIMIT) { + int i; + for (i = 0; i < NNS_TENSOR_RANK_LIMIT - PyList_Size(dims); i++) + /** fill '1's in remaining slots */ + PyList_Append(dims, PyLong_FromLong(1)); + new_dims = dims; + Py_XINCREF(new_dims); + } else { + /** PyList_GetSlice() returns new reference */ + new_dims = PyList_GetSlice(dims, 0, NNS_TENSOR_RANK_LIMIT); + } + + /** swap 'self->dims' */ + Py_XDECREF(self->dims); + self->dims = new_dims; + + Py_RETURN_NONE; +} + +/** + * @brief method impl. for getDims + * @param self : Python type object + * @param args : arguments for the method + */ +static PyObject * +TensorShape_getDims(TensorShapeObject *self, PyObject *args) { + return Py_BuildValue("O", self->dims); +} + +/** + * @brief method impl. for getType + * @param self : Python type object + * @param args : arguments for the method + */ +static PyObject * +TensorShape_getType(TensorShapeObject *self, PyObject *args) { + return Py_BuildValue("O", self->type); +} + +/** + * @brief new callback for custom type object + * @param self : Python type object + * @param args : arguments for the method + * @param kw : keywords for the arguments + */ +static PyObject * +TensorShape_new(PyTypeObject *type, PyObject *args, PyObject *kw) { + TensorShapeObject *self = (TensorShapeObject *) type->tp_alloc(type, 0); + + g_assert(self); + + /** Assign default values */ + self->dims = PyList_New(0); + self->type = PyArray_DescrFromType(NPY_UINT8); + Py_XINCREF(self->type); + + return (PyObject *) self; +} + +/** + * @brief init callback for custom type object + * @param self : Python type object + * @param args : arguments for the method + * @param kw : keywords for the arguments + */ +static int +TensorShape_init(TensorShapeObject *self, PyObject *args, PyObject *kw) { + char *keywords[] = {"dims", "type", NULL}; + PyObject *dims = NULL; + PyObject *type = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "|OO", keywords, &dims, &type)) + return -1; + + if (dims) { + PyObject *none = PyObject_CallMethod((PyObject*) self, (char*) "setDims", "O", dims); + Py_XDECREF(none); + } + + if (type) { + PyArray_Descr* dtype; + if (PyArray_DescrConverter(type, &dtype) != NPY_FAIL) { + /** swap 'self->type' */ + Py_XDECREF(self->type); + self->type = dtype; + Py_XINCREF(dtype); + } else + g_critical("Wrong data type"); + } + + return 0; +} + +/** + * @brief dealloc callback for custom type object + * @param self : Python type object + */ +static void +TensorShape_dealloc(TensorShapeObject *self) { + Py_XDECREF(self->dims); + Py_XDECREF(self->type); + Py_TYPE(self)->tp_free((PyObject *) self); +} + +/** @brief members for custom type object */ +static PyMemberDef TensorShape_members[] = { + {"dims", T_OBJECT_EX, offsetof(TensorShapeObject, dims), 0, NULL}, + {"type", T_OBJECT_EX, offsetof(TensorShapeObject, type), 0, NULL} +}; + +/** @brief methods for custom type object */ +static PyMethodDef TensorShape_methods[] = { + {"setDims", (PyCFunction)TensorShape_setDims, METH_VARARGS | METH_KEYWORDS, NULL}, + {"getDims", (PyCFunction)TensorShape_getDims, METH_VARARGS | METH_KEYWORDS, NULL}, + {"getType", (PyCFunction)TensorShape_getType, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} +}; + +/** @brief Structure for custom type object */ +static PyTypeObject TensorShapeType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "nnstreamer_python.TensorShape", + .tp_doc = "TensorShape type", + .tp_basicsize = sizeof(TensorShapeObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = TensorShape_new, + .tp_init = (initproc) TensorShape_init, + .tp_dealloc = (destructor) TensorShape_dealloc, + .tp_members = TensorShape_members, + .tp_methods = TensorShape_methods +}; + +#if PY_VERSION_HEX >= 0x03000000 +#define RETVAL(x) x +static PyModuleDef nnstreamer_python_module = { + PyModuleDef_HEAD_INIT, "nnstreamer_python3", NULL, -1, NULL +}; +/** @brief module initialization (python 3.x) */ +PyMODINIT_FUNC +PyInit_nnstreamer_python3(void) { +#else +#define RETVAL(x) +static PyMethodDef nnstreamer_python_methods[] = { + {NULL, NULL} +}; +/** @brief module initialization (python 2.x) */ +PyMODINIT_FUNC +initnnstreamer_python2(void) { +#endif + PyObject *type_object = (PyObject*) &TensorShapeType; + PyObject *module; +#if PY_VERSION_HEX >= 0x03000000 + module = PyModule_Create(&nnstreamer_python_module); +#else + module = Py_InitModule("nnstreamer_python2", nnstreamer_python_methods); +#endif + if (module == NULL) + return RETVAL(NULL); + + /** For numpy array init. */ + import_array(); + + /** Check TensorShape type */ + g_assert(!(PyType_Ready(&TensorShapeType) < 0)); + + Py_INCREF(type_object); + PyModule_AddObject(module, "TensorShape", type_object); + + return RETVAL(module); +}