• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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