diff --git a/userland/libs/python_embed/pure.c b/userland/libs/python_embed/pure.c index 377701c..aad5d46 100644 --- a/userland/libs/python_embed/pure.c +++ b/userland/libs/python_embed/pure.c @@ -55,7 +55,7 @@ static PyMethodDef my_native_methods[] = { * self.number = number * * def name(self): - * return '{} {}'.format(self.first, self.last) + * return '{} {} {}'.format(self.first, self.last, self.number) * * class MyDerivedNativeClass(MyNativeClass): * @@ -66,7 +66,7 @@ static PyMethodDef my_native_methods[] = { * self.number2 = number2 * * def name(self): - * return '{} {} {} {} 2'.format(self.first, self.last, self.first2, self.last2) + * return '{} {} {} {} {} {}'.format(self.first, self.last, self.number + 1, self.first2, self.last2, self.number2 + 2) * .... */ typedef struct { @@ -147,15 +147,69 @@ my_native_module_MyNativeClass_init(my_native_module_MyNativeClass *self, PyObje } static PyMemberDef my_native_module_MyNativeClass_members[] = { - {"first", T_OBJECT_EX, offsetof(my_native_module_MyNativeClass, first), 0, - "first name"}, - {"last", T_OBJECT_EX, offsetof(my_native_module_MyNativeClass, last), 0, - "last name"}, {"number", T_INT, offsetof(my_native_module_MyNativeClass, number), 0, "custom number"}, {NULL} }; +static PyObject * +my_native_module_MyNativeClass_getfirst(my_native_module_MyNativeClass *self, void *closure) +{ + (void)closure; + Py_INCREF(self->first); + return self->first; +} + +static int +my_native_module_MyNativeClass_setfirst(my_native_module_MyNativeClass *self, PyObject *value, void *closure) +{ + (void)closure; + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first attribute value must be a string"); + return -1; + } + tmp = self->first; + Py_INCREF(value); + self->first = value; + Py_DECREF(tmp); + return 0; +} + +static PyObject * +my_native_module_MyNativeClass_getlast(my_native_module_MyNativeClass *self, void *closure) +{ + (void)closure; + Py_INCREF(self->last); + return self->last; +} + +static int +my_native_module_MyNativeClass_setlast(my_native_module_MyNativeClass *self, PyObject *value, void *closure) +{ + (void)closure; + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The last attribute value must be a string"); + return -1; + } + tmp = self->last; + Py_INCREF(value); + self->last = value; + Py_DECREF(tmp); + return 0; +} + static PyObject * my_native_module_MyNativeClass_name(my_native_module_MyNativeClass *self, PyObject *Py_UNUSED(ignored)) { @@ -167,9 +221,17 @@ my_native_module_MyNativeClass_name(my_native_module_MyNativeClass *self, PyObje PyErr_SetString(PyExc_AttributeError, "last"); return NULL; } - return PyUnicode_FromFormat("%S %S", self->first, self->last); + return PyUnicode_FromFormat("%S %S %d", self->first, self->last, self->number + 1); } +static PyGetSetDef my_native_module_MyNativeClass_getsetters[] = { + {"first", (getter) my_native_module_MyNativeClass_getfirst, (setter) my_native_module_MyNativeClass_setfirst, + "first name", NULL}, + {"last", (getter) my_native_module_MyNativeClass_getlast, (setter) my_native_module_MyNativeClass_setlast, + "last name", NULL}, + {NULL} /* Sentinel */ +}; + static PyMethodDef my_native_module_MyNativeClass_methods[] = { { "name", @@ -194,6 +256,7 @@ static PyTypeObject my_native_module_MyNativeClassType = { .tp_clear = (inquiry) my_native_module_MyNativeClass_clear, .tp_members = my_native_module_MyNativeClass_members, .tp_methods = my_native_module_MyNativeClass_methods, + .tp_getset = my_native_module_MyNativeClass_getsetters, }; typedef struct { @@ -232,7 +295,7 @@ my_native_module_MyDerivedNativeClass_new(PyTypeObject *type, PyObject *args, Py (void)args; (void)kwds; my_native_module_MyDerivedNativeClass *self; - self = (my_native_module_MyDerivedNativeClass *) type->tp_alloc(type, 0); + self = (my_native_module_MyDerivedNativeClass *) type->tp_base->tp_new(type, args, kwds); if (self != NULL) { self->first2 = PyUnicode_FromString(""); if (self->first2 == NULL) { @@ -281,20 +344,74 @@ my_native_module_MyDerivedNativeClass_init(my_native_module_MyDerivedNativeClass } static PyMemberDef my_native_module_MyDerivedNativeClass_members[] = { - {"first2", T_OBJECT_EX, offsetof(my_native_module_MyDerivedNativeClass, first2), 0, - "first2 name2"}, - {"last2", T_OBJECT_EX, offsetof(my_native_module_MyDerivedNativeClass, last2), 0, - "last2 name2"}, {"number2", T_INT, offsetof(my_native_module_MyDerivedNativeClass, number2), 0, "custom number2"}, {NULL} }; +static PyObject * +my_native_module_MyDerivedNativeClass_getfirst2(my_native_module_MyDerivedNativeClass *self, void *closure) +{ + (void)closure; + Py_INCREF(self->first2); + return self->first2; +} + +static int +my_native_module_MyDerivedNativeClass_setfirst2(my_native_module_MyDerivedNativeClass *self, PyObject *value, void *closure) +{ + (void)closure; + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first2 attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first2 attribute value must be a string"); + return -1; + } + tmp = self->first2; + Py_INCREF(value); + self->first2 = value; + Py_DECREF(tmp); + return 0; +} + +static PyObject * +my_native_module_MyDerivedNativeClass_getlast2(my_native_module_MyDerivedNativeClass *self, void *closure) +{ + (void)closure; + Py_INCREF(self->last2); + return self->last2; +} + +static int +my_native_module_MyDerivedNativeClass_setlast2(my_native_module_MyDerivedNativeClass *self, PyObject *value, void *closure) +{ + (void)closure; + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the last2 attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The last2 attribute value must be a string"); + return -1; + } + tmp = self->last2; + Py_INCREF(value); + self->last2 = value; + Py_DECREF(tmp); + return 0; +} + static PyObject * my_native_module_MyDerivedNativeClass_name2(my_native_module_MyDerivedNativeClass *self, PyObject *Py_UNUSED(ignored)) { if (self->base.first == NULL) { - PyErr_SetString(PyExc_AttributeError, "first"); + PyErr_SetString(PyExc_AttributeError, "first2"); return NULL; } if (self->base.last == NULL) { @@ -302,17 +419,26 @@ my_native_module_MyDerivedNativeClass_name2(my_native_module_MyDerivedNativeClas return NULL; } if (self->first2 == NULL) { - PyErr_SetString(PyExc_AttributeError, "first2"); + PyErr_SetString(PyExc_AttributeError, "first22"); return NULL; } if (self->last2 == NULL) { PyErr_SetString(PyExc_AttributeError, "last2"); return NULL; } - return PyUnicode_FromFormat("%S %S %S %S", - self->base.first, self->base.last, self->first2, self->last2); + return PyUnicode_FromFormat("%S %S %d %S %S %d", + self->base.first, self->base.last, self->base.number + 1, + self->first2, self->last2, self->number2 + 2); } +static PyGetSetDef my_native_module_MyDerivedNativeClass_getsetters[] = { + {"first2", (getter) my_native_module_MyDerivedNativeClass_getfirst2, (setter) my_native_module_MyDerivedNativeClass_setfirst2, + "first2 name", NULL}, + {"last2", (getter) my_native_module_MyDerivedNativeClass_getlast2, (setter) my_native_module_MyDerivedNativeClass_setlast2, + "last2 name", NULL}, + {NULL} /* Sentinel */ +}; + static PyMethodDef my_native_module_MyDerivedNativeClass_methods[] = { { "name2", @@ -337,6 +463,7 @@ static PyTypeObject my_native_module_MyDerivedNativeClassType = { .tp_clear = (inquiry) my_native_module_MyDerivedNativeClass_clear, .tp_members = my_native_module_MyDerivedNativeClass_members, .tp_methods = my_native_module_MyDerivedNativeClass_methods, + .tp_getset = my_native_module_MyDerivedNativeClass_getsetters, }; static PyModuleDef my_native_module = { diff --git a/userland/libs/python_embed/pure.py b/userland/libs/python_embed/pure.py index 82e5fac..99b92e7 100644 --- a/userland/libs/python_embed/pure.py +++ b/userland/libs/python_embed/pure.py @@ -12,18 +12,18 @@ def test_native_method(a, b): def test_native_class(): # Positional arguments. my_native_object = my_native_module.MyNativeClass('ab', 'cd', 13) - assert my_native_object.name() == 'ab cd' + assert my_native_object.name() == 'ab cd 14' # Named arguments. my_native_object = my_native_module.MyNativeClass(first='ef', last='gh', number=13) - assert my_native_object.name() == 'ef gh' + assert my_native_object.name() == 'ef gh 14' # Default values and set property. my_native_object = my_native_module.MyNativeClass() my_native_object.first = 'ih' - assert my_native_object.name() == 'ih ' + assert my_native_object.name() == 'ih 1' my_derived_native_object = my_native_module.MyDerivedNativeClass('ab', 'cd', 13, 'ef', 'gh', 21) - assert my_derived_native_object.name() == 'ab cd' - assert my_derived_native_object.name2() == 'ab cd ef gh' + assert my_derived_native_object.name() == 'ab cd 14' + assert my_derived_native_object.name2() == 'ab cd 14 ef gh 23' return 13 diff --git a/userland/libs/python_embed/pure_cpp.cpp b/userland/libs/python_embed/pure_cpp.cpp index 2828f83..c2b65ce 100644 --- a/userland/libs/python_embed/pure_cpp.cpp +++ b/userland/libs/python_embed/pure_cpp.cpp @@ -4,6 +4,8 @@ #include #include "structmember.h" +#include + /* Define a function in C to be accessible from the Python code. * * .... @@ -33,32 +35,46 @@ static PyMethodDef my_native_methods[] = { }; /* Define a class in C to be accessible from the Python code. - * - * AKA how to write 20 lines of Python in 200 lines of C. - * - * .... - * class MyNativeClass: - * - * def __init__(self, first='', last='', number=0): - * self.first = first - * self.last = last - * self.number = number - * - * def name(self): - * return '{} {}'.format(self.first, self.last) - * - * class MyDerivedNativeClass(MyNativeClass): - * - * def __init__(self, first='', last='', number=0, first2='', last2='', number2=0): - * super().__init__(first, last, number, number) - * self.first2 = first2 - * self.last2 = last2 - * self.number2 = number2 - * - * def name(self): - * return '{} {} {} {} 2'.format(self.first, self.last, self.first2, self.last2) + * and bind data and methods it to a C++ class! * .... */ + +struct MyNativeClass { + std::string first; + std::string last; + int number; + + MyNativeClass( + const std::string& first, + const std::string& last, + int number + ) : first(first), last(last), number(number) {} + + std::string name() { + return first + " " + last; + } +}; + +struct MyDerivedNativeClass : public MyNativeClass { + std::string first2; + std::string last2; + int number2; + + MyDerivedNativeClass( + const std::string& first, + const std::string& last, + int number, + const std::string& first2, + const std::string& last2, + int number2 + ) : MyNativeClass(first, last, number), + first2(first2), last2(last2), number2(number2) {} + + std::string name() { + return first + " " + last + " " + first2 + " " + last2; + } +}; + typedef struct { PyObject_HEAD PyObject *first; @@ -137,15 +153,69 @@ my_native_module_MyNativeClass_init(my_native_module_MyNativeClass *self, PyObje } static PyMemberDef my_native_module_MyNativeClass_members[] = { - {(char*)"first", T_OBJECT_EX, offsetof(my_native_module_MyNativeClass, first), 0, - (char*)"first name"}, - {(char*)"last", T_OBJECT_EX, offsetof(my_native_module_MyNativeClass, last), 0, - (char*)"last name"}, {(char*)"number", T_INT, offsetof(my_native_module_MyNativeClass, number), 0, (char*)"custom number"}, {NULL} }; +static PyObject * +my_native_module_MyNativeClass_getfirst(my_native_module_MyNativeClass *self, void *closure) +{ + (void)closure; + Py_INCREF(self->first); + return self->first; +} + +static int +my_native_module_MyNativeClass_setfirst(my_native_module_MyNativeClass *self, PyObject *value, void *closure) +{ + (void)closure; + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first attribute value must be a string"); + return -1; + } + tmp = self->first; + Py_INCREF(value); + self->first = value; + Py_DECREF(tmp); + return 0; +} + +static PyObject * +my_native_module_MyNativeClass_getlast(my_native_module_MyNativeClass *self, void *closure) +{ + (void)closure; + Py_INCREF(self->last); + return self->last; +} + +static int +my_native_module_MyNativeClass_setlast(my_native_module_MyNativeClass *self, PyObject *value, void *closure) +{ + (void)closure; + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The last attribute value must be a string"); + return -1; + } + tmp = self->last; + Py_INCREF(value); + self->last = value; + Py_DECREF(tmp); + return 0; +} + static PyObject * my_native_module_MyNativeClass_name(my_native_module_MyNativeClass *self, PyObject *Py_UNUSED(ignored)) { @@ -157,7 +227,7 @@ my_native_module_MyNativeClass_name(my_native_module_MyNativeClass *self, PyObje PyErr_SetString(PyExc_AttributeError, "last"); return NULL; } - return PyUnicode_FromFormat("%S %S", self->first, self->last); + return PyUnicode_FromFormat("%S %S %d", self->first, self->last, self->number + 1); } static PyMethodDef my_native_module_MyNativeClass_methods[] = { @@ -170,6 +240,14 @@ static PyMethodDef my_native_module_MyNativeClass_methods[] = { {NULL} }; +static PyGetSetDef my_native_module_MyNativeClass_getsetters[] = { + {(char *)"first", (getter) my_native_module_MyNativeClass_getfirst, (setter) my_native_module_MyNativeClass_setfirst, + (char *)"first name", NULL}, + {(char *)"last", (getter) my_native_module_MyNativeClass_getlast, (setter) my_native_module_MyNativeClass_setlast, + (char *)"last name", NULL}, + {NULL} /* Sentinel */ +}; + static PyTypeObject my_native_module_MyNativeClassType = { PyVarObject_HEAD_INIT(NULL, 0) }; @@ -259,15 +337,69 @@ my_native_module_MyDerivedNativeClass_init(my_native_module_MyDerivedNativeClass } static PyMemberDef my_native_module_MyDerivedNativeClass_members[] = { - {(char*)"first2", T_OBJECT_EX, offsetof(my_native_module_MyDerivedNativeClass, first2), 0, - (char*)"first2 name2"}, - {(char*)"last2", T_OBJECT_EX, offsetof(my_native_module_MyDerivedNativeClass, last2), 0, - (char*)"last2 name2"}, {(char*)"number2", T_INT, offsetof(my_native_module_MyDerivedNativeClass, number2), 0, (char*)"custom number2"}, {NULL} }; +static PyObject * +my_native_module_MyDerivedNativeClass_getfirst2(my_native_module_MyDerivedNativeClass *self, void *closure) +{ + (void)closure; + Py_INCREF(self->first2); + return self->first2; +} + +static int +my_native_module_MyDerivedNativeClass_setfirst2(my_native_module_MyDerivedNativeClass *self, PyObject *value, void *closure) +{ + (void)closure; + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the first2 attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The first2 attribute value must be a string"); + return -1; + } + tmp = self->first2; + Py_INCREF(value); + self->first2 = value; + Py_DECREF(tmp); + return 0; +} + +static PyObject * +my_native_module_MyDerivedNativeClass_getlast2(my_native_module_MyDerivedNativeClass *self, void *closure) +{ + (void)closure; + Py_INCREF(self->last2); + return self->last2; +} + +static int +my_native_module_MyDerivedNativeClass_setlast2(my_native_module_MyDerivedNativeClass *self, PyObject *value, void *closure) +{ + (void)closure; + PyObject *tmp; + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, "Cannot delete the last2 attribute"); + return -1; + } + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "The last2 attribute value must be a string"); + return -1; + } + tmp = self->last2; + Py_INCREF(value); + self->last2 = value; + Py_DECREF(tmp); + return 0; +} + static PyObject * my_native_module_MyDerivedNativeClass_name2(my_native_module_MyDerivedNativeClass *self, PyObject *Py_UNUSED(ignored)) { @@ -287,9 +419,19 @@ my_native_module_MyDerivedNativeClass_name2(my_native_module_MyDerivedNativeClas PyErr_SetString(PyExc_AttributeError, "last2"); return NULL; } - return PyUnicode_FromFormat("%S %S %S %S", self->base.first, self->base.last, self->first2, self->last2); + return PyUnicode_FromFormat("%S %S %d %S %S %d", + self->base.first, self->base.last, self->base.number + 1, + self->first2, self->last2, self->number2 + 2); } +static PyGetSetDef my_native_module_MyDerivedNativeClass_getsetters[] = { + {(char *)"first2", (getter) my_native_module_MyDerivedNativeClass_getfirst2, (setter) my_native_module_MyDerivedNativeClass_setfirst2, + (char *)"first2 name", NULL}, + {(char *)"last2", (getter) my_native_module_MyDerivedNativeClass_getlast2, (setter) my_native_module_MyDerivedNativeClass_setlast2, + (char *)"last2 name", NULL}, + {NULL} /* Sentinel */ +}; + static PyMethodDef my_native_module_MyDerivedNativeClass_methods[] = { { "name2", @@ -369,6 +511,7 @@ main(int argc, char *argv[]) my_native_module_MyNativeClassType.tp_clear = (inquiry) my_native_module_MyNativeClass_clear; my_native_module_MyNativeClassType.tp_members = my_native_module_MyNativeClass_members; my_native_module_MyNativeClassType.tp_methods = my_native_module_MyNativeClass_methods; + my_native_module_MyNativeClassType.tp_getset = my_native_module_MyNativeClass_getsetters; my_native_module_MyDerivedNativeClassType.tp_name = "my_native_module.MyDerivedNativeClass"; my_native_module_MyDerivedNativeClassType.tp_doc = "My native class"; @@ -382,6 +525,7 @@ main(int argc, char *argv[]) my_native_module_MyDerivedNativeClassType.tp_clear = (inquiry) my_native_module_MyDerivedNativeClass_clear; my_native_module_MyDerivedNativeClassType.tp_members = my_native_module_MyDerivedNativeClass_members; my_native_module_MyDerivedNativeClassType.tp_methods = my_native_module_MyDerivedNativeClass_methods; + my_native_module_MyDerivedNativeClassType.tp_getset = my_native_module_MyDerivedNativeClass_getsetters; PyImport_AppendInittab("my_native_module", &my_native_module_init_func); Py_Initialize();