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