1 #define PY_SSIZE_T_CLEAN
2 #include <Python.h>
3 #include <stddef.h> /* for offsetof() */
4
5 typedef struct {
6 PyObject_HEAD
7 PyObject *first; /* first name */
8 PyObject *last; /* last name */
9 int number;
10 } CustomObject;
11
12 static void
Custom_dealloc(CustomObject * self)13 Custom_dealloc(CustomObject *self)
14 {
15 Py_XDECREF(self->first);
16 Py_XDECREF(self->last);
17 Py_TYPE(self)->tp_free((PyObject *) self);
18 }
19
20 static PyObject *
Custom_new(PyTypeObject * type,PyObject * args,PyObject * kwds)21 Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
22 {
23 CustomObject *self;
24 self = (CustomObject *) type->tp_alloc(type, 0);
25 if (self != NULL) {
26 self->first = PyUnicode_FromString("");
27 if (self->first == NULL) {
28 Py_DECREF(self);
29 return NULL;
30 }
31 self->last = PyUnicode_FromString("");
32 if (self->last == NULL) {
33 Py_DECREF(self);
34 return NULL;
35 }
36 self->number = 0;
37 }
38 return (PyObject *) self;
39 }
40
41 static int
Custom_init(CustomObject * self,PyObject * args,PyObject * kwds)42 Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
43 {
44 static char *kwlist[] = {"first", "last", "number", NULL};
45 PyObject *first = NULL, *last = NULL;
46
47 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
48 &first, &last,
49 &self->number))
50 return -1;
51
52 if (first) {
53 Py_XSETREF(self->first, Py_NewRef(first));
54 }
55 if (last) {
56 Py_XSETREF(self->last, Py_NewRef(last));
57 }
58 return 0;
59 }
60
61 static PyMemberDef Custom_members[] = {
62 {"first", Py_T_OBJECT_EX, offsetof(CustomObject, first), 0,
63 "first name"},
64 {"last", Py_T_OBJECT_EX, offsetof(CustomObject, last), 0,
65 "last name"},
66 {"number", Py_T_INT, offsetof(CustomObject, number), 0,
67 "custom number"},
68 {NULL} /* Sentinel */
69 };
70
71 static PyObject *
Custom_name(CustomObject * self,PyObject * Py_UNUSED (ignored))72 Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
73 {
74 if (self->first == NULL) {
75 PyErr_SetString(PyExc_AttributeError, "first");
76 return NULL;
77 }
78 if (self->last == NULL) {
79 PyErr_SetString(PyExc_AttributeError, "last");
80 return NULL;
81 }
82 return PyUnicode_FromFormat("%S %S", self->first, self->last);
83 }
84
85 static PyMethodDef Custom_methods[] = {
86 {"name", (PyCFunction) Custom_name, METH_NOARGS,
87 "Return the name, combining the first and last name"
88 },
89 {NULL} /* Sentinel */
90 };
91
92 static PyTypeObject CustomType = {
93 .ob_base = PyVarObject_HEAD_INIT(NULL, 0)
94 .tp_name = "custom2.Custom",
95 .tp_doc = PyDoc_STR("Custom objects"),
96 .tp_basicsize = sizeof(CustomObject),
97 .tp_itemsize = 0,
98 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
99 .tp_new = Custom_new,
100 .tp_init = (initproc) Custom_init,
101 .tp_dealloc = (destructor) Custom_dealloc,
102 .tp_members = Custom_members,
103 .tp_methods = Custom_methods,
104 };
105
106 static PyModuleDef custommodule = {
107 .m_base =PyModuleDef_HEAD_INIT,
108 .m_name = "custom2",
109 .m_doc = "Example module that creates an extension type.",
110 .m_size = -1,
111 };
112
113 PyMODINIT_FUNC
PyInit_custom2(void)114 PyInit_custom2(void)
115 {
116 PyObject *m;
117 if (PyType_Ready(&CustomType) < 0)
118 return NULL;
119
120 m = PyModule_Create(&custommodule);
121 if (m == NULL)
122 return NULL;
123
124 if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
125 Py_DECREF(m);
126 return NULL;
127 }
128
129 return m;
130 }
131