1 #include <Python.h>
2 #include "structmember.h"
3
4 typedef struct {
5 PyObject_HEAD
6 PyObject *first; /* first name */
7 PyObject *last; /* last name */
8 int number;
9 } CustomObject;
10
11 static int
Custom_traverse(CustomObject * self,visitproc visit,void * arg)12 Custom_traverse(CustomObject *self, visitproc visit, void *arg)
13 {
14 Py_VISIT(self->first);
15 Py_VISIT(self->last);
16 return 0;
17 }
18
19 static int
Custom_clear(CustomObject * self)20 Custom_clear(CustomObject *self)
21 {
22 Py_CLEAR(self->first);
23 Py_CLEAR(self->last);
24 return 0;
25 }
26
27 static void
Custom_dealloc(CustomObject * self)28 Custom_dealloc(CustomObject *self)
29 {
30 PyObject_GC_UnTrack(self);
31 Custom_clear(self);
32 Py_TYPE(self)->tp_free((PyObject *) self);
33 }
34
35 static PyObject *
Custom_new(PyTypeObject * type,PyObject * args,PyObject * kwds)36 Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
37 {
38 CustomObject *self;
39 self = (CustomObject *) type->tp_alloc(type, 0);
40 if (self != NULL) {
41 self->first = PyUnicode_FromString("");
42 if (self->first == NULL) {
43 Py_DECREF(self);
44 return NULL;
45 }
46 self->last = PyUnicode_FromString("");
47 if (self->last == NULL) {
48 Py_DECREF(self);
49 return NULL;
50 }
51 self->number = 0;
52 }
53 return (PyObject *) self;
54 }
55
56 static int
Custom_init(CustomObject * self,PyObject * args,PyObject * kwds)57 Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
58 {
59 static char *kwlist[] = {"first", "last", "number", NULL};
60 PyObject *first = NULL, *last = NULL, *tmp;
61
62 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
63 &first, &last,
64 &self->number))
65 return -1;
66
67 if (first) {
68 tmp = self->first;
69 Py_INCREF(first);
70 self->first = first;
71 Py_DECREF(tmp);
72 }
73 if (last) {
74 tmp = self->last;
75 Py_INCREF(last);
76 self->last = last;
77 Py_DECREF(tmp);
78 }
79 return 0;
80 }
81
82 static PyMemberDef Custom_members[] = {
83 {"number", T_INT, offsetof(CustomObject, number), 0,
84 "custom number"},
85 {NULL} /* Sentinel */
86 };
87
88 static PyObject *
Custom_getfirst(CustomObject * self,void * closure)89 Custom_getfirst(CustomObject *self, void *closure)
90 {
91 Py_INCREF(self->first);
92 return self->first;
93 }
94
95 static int
Custom_setfirst(CustomObject * self,PyObject * value,void * closure)96 Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
97 {
98 if (value == NULL) {
99 PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
100 return -1;
101 }
102 if (!PyUnicode_Check(value)) {
103 PyErr_SetString(PyExc_TypeError,
104 "The first attribute value must be a string");
105 return -1;
106 }
107 Py_INCREF(value);
108 Py_CLEAR(self->first);
109 self->first = value;
110 return 0;
111 }
112
113 static PyObject *
Custom_getlast(CustomObject * self,void * closure)114 Custom_getlast(CustomObject *self, void *closure)
115 {
116 Py_INCREF(self->last);
117 return self->last;
118 }
119
120 static int
Custom_setlast(CustomObject * self,PyObject * value,void * closure)121 Custom_setlast(CustomObject *self, PyObject *value, void *closure)
122 {
123 if (value == NULL) {
124 PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
125 return -1;
126 }
127 if (!PyUnicode_Check(value)) {
128 PyErr_SetString(PyExc_TypeError,
129 "The last attribute value must be a string");
130 return -1;
131 }
132 Py_INCREF(value);
133 Py_CLEAR(self->last);
134 self->last = value;
135 return 0;
136 }
137
138 static PyGetSetDef Custom_getsetters[] = {
139 {"first", (getter) Custom_getfirst, (setter) Custom_setfirst,
140 "first name", NULL},
141 {"last", (getter) Custom_getlast, (setter) Custom_setlast,
142 "last name", NULL},
143 {NULL} /* Sentinel */
144 };
145
146 static PyObject *
Custom_name(CustomObject * self,PyObject * Py_UNUSED (ignored))147 Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
148 {
149 return PyUnicode_FromFormat("%S %S", self->first, self->last);
150 }
151
152 static PyMethodDef Custom_methods[] = {
153 {"name", (PyCFunction) Custom_name, METH_NOARGS,
154 "Return the name, combining the first and last name"
155 },
156 {NULL} /* Sentinel */
157 };
158
159 static PyTypeObject CustomType = {
160 PyVarObject_HEAD_INIT(NULL, 0)
161 .tp_name = "custom4.Custom",
162 .tp_doc = "Custom objects",
163 .tp_basicsize = sizeof(CustomObject),
164 .tp_itemsize = 0,
165 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
166 .tp_new = Custom_new,
167 .tp_init = (initproc) Custom_init,
168 .tp_dealloc = (destructor) Custom_dealloc,
169 .tp_traverse = (traverseproc) Custom_traverse,
170 .tp_clear = (inquiry) Custom_clear,
171 .tp_members = Custom_members,
172 .tp_methods = Custom_methods,
173 .tp_getset = Custom_getsetters,
174 };
175
176 static PyModuleDef custommodule = {
177 PyModuleDef_HEAD_INIT,
178 .m_name = "custom4",
179 .m_doc = "Example module that creates an extension type.",
180 .m_size = -1,
181 };
182
183 PyMODINIT_FUNC
PyInit_custom4(void)184 PyInit_custom4(void)
185 {
186 PyObject *m;
187 if (PyType_Ready(&CustomType) < 0)
188 return NULL;
189
190 m = PyModule_Create(&custommodule);
191 if (m == NULL)
192 return NULL;
193
194 Py_INCREF(&CustomType);
195 PyModule_AddObject(m, "Custom", (PyObject *) &CustomType);
196 return m;
197 }
198