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