• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #define PY_SSIZE_T_CLEAN
2 #include <Python.h>
3 #include "structmember.h"
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, *tmp;
62 
63     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
64                                      &first, &last,
65                                      &self->number))
66         return -1;
67 
68     if (first) {
69         tmp = self->first;
70         Py_INCREF(first);
71         self->first = first;
72         Py_DECREF(tmp);
73     }
74     if (last) {
75         tmp = self->last;
76         Py_INCREF(last);
77         self->last = last;
78         Py_DECREF(tmp);
79     }
80     return 0;
81 }
82 
83 static PyMemberDef Custom_members[] = {
84     {"number", T_INT, offsetof(CustomObject, number), 0,
85      "custom number"},
86     {NULL}  /* Sentinel */
87 };
88 
89 static PyObject *
Custom_getfirst(CustomObject * self,void * closure)90 Custom_getfirst(CustomObject *self, void *closure)
91 {
92     Py_INCREF(self->first);
93     return self->first;
94 }
95 
96 static int
Custom_setfirst(CustomObject * self,PyObject * value,void * closure)97 Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
98 {
99     if (value == NULL) {
100         PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
101         return -1;
102     }
103     if (!PyUnicode_Check(value)) {
104         PyErr_SetString(PyExc_TypeError,
105                         "The first attribute value must be a string");
106         return -1;
107     }
108     Py_INCREF(value);
109     Py_CLEAR(self->first);
110     self->first = value;
111     return 0;
112 }
113 
114 static PyObject *
Custom_getlast(CustomObject * self,void * closure)115 Custom_getlast(CustomObject *self, void *closure)
116 {
117     Py_INCREF(self->last);
118     return self->last;
119 }
120 
121 static int
Custom_setlast(CustomObject * self,PyObject * value,void * closure)122 Custom_setlast(CustomObject *self, PyObject *value, void *closure)
123 {
124     if (value == NULL) {
125         PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
126         return -1;
127     }
128     if (!PyUnicode_Check(value)) {
129         PyErr_SetString(PyExc_TypeError,
130                         "The last attribute value must be a string");
131         return -1;
132     }
133     Py_INCREF(value);
134     Py_CLEAR(self->last);
135     self->last = value;
136     return 0;
137 }
138 
139 static PyGetSetDef Custom_getsetters[] = {
140     {"first", (getter) Custom_getfirst, (setter) Custom_setfirst,
141      "first name", NULL},
142     {"last", (getter) Custom_getlast, (setter) Custom_setlast,
143      "last name", NULL},
144     {NULL}  /* Sentinel */
145 };
146 
147 static PyObject *
Custom_name(CustomObject * self,PyObject * Py_UNUSED (ignored))148 Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
149 {
150     return PyUnicode_FromFormat("%S %S", self->first, self->last);
151 }
152 
153 static PyMethodDef Custom_methods[] = {
154     {"name", (PyCFunction) Custom_name, METH_NOARGS,
155      "Return the name, combining the first and last name"
156     },
157     {NULL}  /* Sentinel */
158 };
159 
160 static PyTypeObject CustomType = {
161     PyVarObject_HEAD_INIT(NULL, 0)
162     .tp_name = "custom4.Custom",
163     .tp_doc = "Custom objects",
164     .tp_basicsize = sizeof(CustomObject),
165     .tp_itemsize = 0,
166     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
167     .tp_new = Custom_new,
168     .tp_init = (initproc) Custom_init,
169     .tp_dealloc = (destructor) Custom_dealloc,
170     .tp_traverse = (traverseproc) Custom_traverse,
171     .tp_clear = (inquiry) Custom_clear,
172     .tp_members = Custom_members,
173     .tp_methods = Custom_methods,
174     .tp_getset = Custom_getsetters,
175 };
176 
177 static PyModuleDef custommodule = {
178     PyModuleDef_HEAD_INIT,
179     .m_name = "custom4",
180     .m_doc = "Example module that creates an extension type.",
181     .m_size = -1,
182 };
183 
184 PyMODINIT_FUNC
PyInit_custom4(void)185 PyInit_custom4(void)
186 {
187     PyObject *m;
188     if (PyType_Ready(&CustomType) < 0)
189         return NULL;
190 
191     m = PyModule_Create(&custommodule);
192     if (m == NULL)
193         return NULL;
194 
195     Py_INCREF(&CustomType);
196     if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) {
197         Py_DECREF(&CustomType);
198         Py_DECREF(m);
199         return NULL;
200     }
201 
202     return m;
203 }
204