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