1/* Descriptors -- a new, flexible way to describe attributes */
2
3#include "Python.h"
4#include "structmember.h" /* Why is this not included in Python.h? */
5
6static void
7descr_dealloc(PyDescrObject *descr)
8{
9    _PyObject_GC_UNTRACK(descr);
10    Py_XDECREF(descr->d_type);
11    Py_XDECREF(descr->d_name);
12    PyObject_GC_Del(descr);
13}
14
15static char *
16descr_name(PyDescrObject *descr)
17{
18    if (descr->d_name != NULL && PyString_Check(descr->d_name))
19        return PyString_AS_STRING(descr->d_name);
20    else
21        return "?";
22}
23
24static PyObject *
25descr_repr(PyDescrObject *descr, char *format)
26{
27    return PyString_FromFormat(format, descr_name(descr),
28                               descr->d_type->tp_name);
29}
30
31static PyObject *
32method_repr(PyMethodDescrObject *descr)
33{
34    return descr_repr((PyDescrObject *)descr,
35                      "<method '%s' of '%s' objects>");
36}
37
38static PyObject *
39member_repr(PyMemberDescrObject *descr)
40{
41    return descr_repr((PyDescrObject *)descr,
42                      "<member '%s' of '%s' objects>");
43}
44
45static PyObject *
46getset_repr(PyGetSetDescrObject *descr)
47{
48    return descr_repr((PyDescrObject *)descr,
49                      "<attribute '%s' of '%s' objects>");
50}
51
52static PyObject *
53wrapperdescr_repr(PyWrapperDescrObject *descr)
54{
55    return descr_repr((PyDescrObject *)descr,
56                      "<slot wrapper '%s' of '%s' objects>");
57}
58
59static int
60descr_check(PyDescrObject *descr, PyObject *obj, PyObject **pres)
61{
62    if (obj == NULL) {
63        Py_INCREF(descr);
64        *pres = (PyObject *)descr;
65        return 1;
66    }
67    if (!PyObject_TypeCheck(obj, descr->d_type)) {
68        PyErr_Format(PyExc_TypeError,
69                     "descriptor '%s' for '%s' objects "
70                     "doesn't apply to '%s' object",
71                     descr_name((PyDescrObject *)descr),
72                     descr->d_type->tp_name,
73                     obj->ob_type->tp_name);
74        *pres = NULL;
75        return 1;
76    }
77    return 0;
78}
79
80static PyObject *
81classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type)
82{
83    /* Ensure a valid type.  Class methods ignore obj. */
84    if (type == NULL) {
85        if (obj != NULL)
86            type = (PyObject *)obj->ob_type;
87        else {
88            /* Wot - no type?! */
89            PyErr_Format(PyExc_TypeError,
90                         "descriptor '%s' for type '%s' "
91                         "needs either an object or a type",
92                         descr_name((PyDescrObject *)descr),
93                         descr->d_type->tp_name);
94            return NULL;
95        }
96    }
97    if (!PyType_Check(type)) {
98        PyErr_Format(PyExc_TypeError,
99                     "descriptor '%s' for type '%s' "
100                     "needs a type, not a '%s' as arg 2",
101                     descr_name((PyDescrObject *)descr),
102                     descr->d_type->tp_name,
103                     type->ob_type->tp_name);
104        return NULL;
105    }
106    if (!PyType_IsSubtype((PyTypeObject *)type, descr->d_type)) {
107        PyErr_Format(PyExc_TypeError,
108                     "descriptor '%s' for type '%s' "
109                     "doesn't apply to type '%s'",
110                     descr_name((PyDescrObject *)descr),
111                     descr->d_type->tp_name,
112                     ((PyTypeObject *)type)->tp_name);
113        return NULL;
114    }
115    return PyCFunction_New(descr->d_method, type);
116}
117
118static PyObject *
119method_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type)
120{
121    PyObject *res;
122
123    if (descr_check((PyDescrObject *)descr, obj, &res))
124        return res;
125    return PyCFunction_New(descr->d_method, obj);
126}
127
128static PyObject *
129member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type)
130{
131    PyObject *res;
132
133    if (descr_check((PyDescrObject *)descr, obj, &res))
134        return res;
135    return PyMember_GetOne((char *)obj, descr->d_member);
136}
137
138static PyObject *
139getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type)
140{
141    PyObject *res;
142
143    if (descr_check((PyDescrObject *)descr, obj, &res))
144        return res;
145    if (descr->d_getset->get != NULL)
146        return descr->d_getset->get(obj, descr->d_getset->closure);
147    PyErr_Format(PyExc_AttributeError,
148                 "attribute '%.300s' of '%.100s' objects is not readable",
149                 descr_name((PyDescrObject *)descr),
150                 descr->d_type->tp_name);
151    return NULL;
152}
153
154static PyObject *
155wrapperdescr_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type)
156{
157    PyObject *res;
158
159    if (descr_check((PyDescrObject *)descr, obj, &res))
160        return res;
161    return PyWrapper_New((PyObject *)descr, obj);
162}
163
164static int
165descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,
166               int *pres)
167{
168    assert(obj != NULL);
169    if (!PyObject_TypeCheck(obj, descr->d_type)) {
170        PyErr_Format(PyExc_TypeError,
171                     "descriptor '%.200s' for '%.100s' objects "
172                     "doesn't apply to '%.100s' object",
173                     descr_name(descr),
174                     descr->d_type->tp_name,
175                     obj->ob_type->tp_name);
176        *pres = -1;
177        return 1;
178    }
179    return 0;
180}
181
182static int
183member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)
184{
185    int res;
186
187    if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
188        return res;
189    return PyMember_SetOne((char *)obj, descr->d_member, value);
190}
191
192static int
193getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
194{
195    int res;
196
197    if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
198        return res;
199    if (descr->d_getset->set != NULL)
200        return descr->d_getset->set(obj, value,
201                                    descr->d_getset->closure);
202    PyErr_Format(PyExc_AttributeError,
203                 "attribute '%.300s' of '%.100s' objects is not writable",
204                 descr_name((PyDescrObject *)descr),
205                 descr->d_type->tp_name);
206    return -1;
207}
208
209static PyObject *
210methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
211{
212    Py_ssize_t argc;
213    PyObject *self, *func, *result;
214
215    /* Make sure that the first argument is acceptable as 'self' */
216    assert(PyTuple_Check(args));
217    argc = PyTuple_GET_SIZE(args);
218    if (argc < 1) {
219        PyErr_Format(PyExc_TypeError,
220                     "descriptor '%.300s' of '%.100s' "
221                     "object needs an argument",
222                     descr_name((PyDescrObject *)descr),
223                     descr->d_type->tp_name);
224        return NULL;
225    }
226    self = PyTuple_GET_ITEM(args, 0);
227    if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
228                                  (PyObject *)(descr->d_type))) {
229        PyErr_Format(PyExc_TypeError,
230                     "descriptor '%.200s' "
231                     "requires a '%.100s' object "
232                     "but received a '%.100s'",
233                     descr_name((PyDescrObject *)descr),
234                     descr->d_type->tp_name,
235                     self->ob_type->tp_name);
236        return NULL;
237    }
238
239    func = PyCFunction_New(descr->d_method, self);
240    if (func == NULL)
241        return NULL;
242    args = PyTuple_GetSlice(args, 1, argc);
243    if (args == NULL) {
244        Py_DECREF(func);
245        return NULL;
246    }
247    result = PyEval_CallObjectWithKeywords(func, args, kwds);
248    Py_DECREF(args);
249    Py_DECREF(func);
250    return result;
251}
252
253static PyObject *
254classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
255                      PyObject *kwds)
256{
257    Py_ssize_t argc;
258    PyObject *self, *func, *result;
259
260    /* Make sure that the first argument is acceptable as 'self' */
261    assert(PyTuple_Check(args));
262    argc = PyTuple_GET_SIZE(args);
263    if (argc < 1) {
264        PyErr_Format(PyExc_TypeError,
265                     "descriptor '%s' of '%.100s' "
266                     "object needs an argument",
267                     descr_name((PyDescrObject *)descr),
268                     descr->d_type->tp_name);
269        return NULL;
270    }
271    self = PyTuple_GET_ITEM(args, 0);
272    if (!PyType_Check(self)) {
273        PyErr_Format(PyExc_TypeError,
274                     "descriptor '%s' requires a type "
275                     "but received a '%.100s'",
276                     descr_name((PyDescrObject *)descr),
277                     self->ob_type->tp_name);
278        return NULL;
279    }
280    if (!PyType_IsSubtype((PyTypeObject *)self, descr->d_type)) {
281        PyErr_Format(PyExc_TypeError,
282                     "descriptor '%s' "
283                     "requires a subtype of '%.100s' "
284                     "but received '%.100s",
285                     descr_name((PyDescrObject *)descr),
286                     descr->d_type->tp_name,
287                     self->ob_type->tp_name);
288        return NULL;
289    }
290
291    func = PyCFunction_New(descr->d_method, self);
292    if (func == NULL)
293        return NULL;
294    args = PyTuple_GetSlice(args, 1, argc);
295    if (args == NULL) {
296        Py_DECREF(func);
297        return NULL;
298    }
299    result = PyEval_CallObjectWithKeywords(func, args, kwds);
300    Py_DECREF(func);
301    Py_DECREF(args);
302    return result;
303}
304
305static PyObject *
306wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
307{
308    Py_ssize_t argc;
309    PyObject *self, *func, *result;
310
311    /* Make sure that the first argument is acceptable as 'self' */
312    assert(PyTuple_Check(args));
313    argc = PyTuple_GET_SIZE(args);
314    if (argc < 1) {
315        PyErr_Format(PyExc_TypeError,
316                     "descriptor '%.300s' of '%.100s' "
317                     "object needs an argument",
318                     descr_name((PyDescrObject *)descr),
319                     descr->d_type->tp_name);
320        return NULL;
321    }
322    self = PyTuple_GET_ITEM(args, 0);
323    if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
324                                  (PyObject *)(descr->d_type))) {
325        PyErr_Format(PyExc_TypeError,
326                     "descriptor '%.200s' "
327                     "requires a '%.100s' object "
328                     "but received a '%.100s'",
329                     descr_name((PyDescrObject *)descr),
330                     descr->d_type->tp_name,
331                     self->ob_type->tp_name);
332        return NULL;
333    }
334
335    func = PyWrapper_New((PyObject *)descr, self);
336    if (func == NULL)
337        return NULL;
338    args = PyTuple_GetSlice(args, 1, argc);
339    if (args == NULL) {
340        Py_DECREF(func);
341        return NULL;
342    }
343    result = PyEval_CallObjectWithKeywords(func, args, kwds);
344    Py_DECREF(args);
345    Py_DECREF(func);
346    return result;
347}
348
349static PyObject *
350method_get_doc(PyMethodDescrObject *descr, void *closure)
351{
352    if (descr->d_method->ml_doc == NULL) {
353        Py_INCREF(Py_None);
354        return Py_None;
355    }
356    return PyString_FromString(descr->d_method->ml_doc);
357}
358
359static PyMemberDef descr_members[] = {
360    {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},
361    {"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},
362    {0}
363};
364
365static PyGetSetDef method_getset[] = {
366    {"__doc__", (getter)method_get_doc},
367    {0}
368};
369
370static PyObject *
371member_get_doc(PyMemberDescrObject *descr, void *closure)
372{
373    if (descr->d_member->doc == NULL) {
374        Py_INCREF(Py_None);
375        return Py_None;
376    }
377    return PyString_FromString(descr->d_member->doc);
378}
379
380static PyGetSetDef member_getset[] = {
381    {"__doc__", (getter)member_get_doc},
382    {0}
383};
384
385static PyObject *
386getset_get_doc(PyGetSetDescrObject *descr, void *closure)
387{
388    if (descr->d_getset->doc == NULL) {
389        Py_INCREF(Py_None);
390        return Py_None;
391    }
392    return PyString_FromString(descr->d_getset->doc);
393}
394
395static PyGetSetDef getset_getset[] = {
396    {"__doc__", (getter)getset_get_doc},
397    {0}
398};
399
400static PyObject *
401wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure)
402{
403    if (descr->d_base->doc == NULL) {
404        Py_INCREF(Py_None);
405        return Py_None;
406    }
407    return PyString_FromString(descr->d_base->doc);
408}
409
410static PyGetSetDef wrapperdescr_getset[] = {
411    {"__doc__", (getter)wrapperdescr_get_doc},
412    {0}
413};
414
415static int
416descr_traverse(PyObject *self, visitproc visit, void *arg)
417{
418    PyDescrObject *descr = (PyDescrObject *)self;
419    Py_VISIT(descr->d_type);
420    return 0;
421}
422
423static PyTypeObject PyMethodDescr_Type = {
424    PyVarObject_HEAD_INIT(&PyType_Type, 0)
425    "method_descriptor",
426    sizeof(PyMethodDescrObject),
427    0,
428    (destructor)descr_dealloc,                  /* tp_dealloc */
429    0,                                          /* tp_print */
430    0,                                          /* tp_getattr */
431    0,                                          /* tp_setattr */
432    0,                                          /* tp_compare */
433    (reprfunc)method_repr,                      /* tp_repr */
434    0,                                          /* tp_as_number */
435    0,                                          /* tp_as_sequence */
436    0,                                          /* tp_as_mapping */
437    0,                                          /* tp_hash */
438    (ternaryfunc)methoddescr_call,              /* tp_call */
439    0,                                          /* tp_str */
440    PyObject_GenericGetAttr,                    /* tp_getattro */
441    0,                                          /* tp_setattro */
442    0,                                          /* tp_as_buffer */
443    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
444    0,                                          /* tp_doc */
445    descr_traverse,                             /* tp_traverse */
446    0,                                          /* tp_clear */
447    0,                                          /* tp_richcompare */
448    0,                                          /* tp_weaklistoffset */
449    0,                                          /* tp_iter */
450    0,                                          /* tp_iternext */
451    0,                                          /* tp_methods */
452    descr_members,                              /* tp_members */
453    method_getset,                              /* tp_getset */
454    0,                                          /* tp_base */
455    0,                                          /* tp_dict */
456    (descrgetfunc)method_get,                   /* tp_descr_get */
457    0,                                          /* tp_descr_set */
458};
459
460/* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */
461static PyTypeObject PyClassMethodDescr_Type = {
462    PyVarObject_HEAD_INIT(&PyType_Type, 0)
463    "classmethod_descriptor",
464    sizeof(PyMethodDescrObject),
465    0,
466    (destructor)descr_dealloc,                  /* tp_dealloc */
467    0,                                          /* tp_print */
468    0,                                          /* tp_getattr */
469    0,                                          /* tp_setattr */
470    0,                                          /* tp_compare */
471    (reprfunc)method_repr,                      /* tp_repr */
472    0,                                          /* tp_as_number */
473    0,                                          /* tp_as_sequence */
474    0,                                          /* tp_as_mapping */
475    0,                                          /* tp_hash */
476    (ternaryfunc)classmethoddescr_call,         /* tp_call */
477    0,                                          /* tp_str */
478    PyObject_GenericGetAttr,                    /* tp_getattro */
479    0,                                          /* tp_setattro */
480    0,                                          /* tp_as_buffer */
481    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
482    0,                                          /* tp_doc */
483    descr_traverse,                             /* tp_traverse */
484    0,                                          /* tp_clear */
485    0,                                          /* tp_richcompare */
486    0,                                          /* tp_weaklistoffset */
487    0,                                          /* tp_iter */
488    0,                                          /* tp_iternext */
489    0,                                          /* tp_methods */
490    descr_members,                              /* tp_members */
491    method_getset,                              /* tp_getset */
492    0,                                          /* tp_base */
493    0,                                          /* tp_dict */
494    (descrgetfunc)classmethod_get,              /* tp_descr_get */
495    0,                                          /* tp_descr_set */
496};
497
498PyTypeObject PyMemberDescr_Type = {
499    PyVarObject_HEAD_INIT(&PyType_Type, 0)
500    "member_descriptor",
501    sizeof(PyMemberDescrObject),
502    0,
503    (destructor)descr_dealloc,                  /* tp_dealloc */
504    0,                                          /* tp_print */
505    0,                                          /* tp_getattr */
506    0,                                          /* tp_setattr */
507    0,                                          /* tp_compare */
508    (reprfunc)member_repr,                      /* tp_repr */
509    0,                                          /* tp_as_number */
510    0,                                          /* tp_as_sequence */
511    0,                                          /* tp_as_mapping */
512    0,                                          /* tp_hash */
513    0,                                          /* tp_call */
514    0,                                          /* tp_str */
515    PyObject_GenericGetAttr,                    /* tp_getattro */
516    0,                                          /* tp_setattro */
517    0,                                          /* tp_as_buffer */
518    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
519    0,                                          /* tp_doc */
520    descr_traverse,                             /* tp_traverse */
521    0,                                          /* tp_clear */
522    0,                                          /* tp_richcompare */
523    0,                                          /* tp_weaklistoffset */
524    0,                                          /* tp_iter */
525    0,                                          /* tp_iternext */
526    0,                                          /* tp_methods */
527    descr_members,                              /* tp_members */
528    member_getset,                              /* tp_getset */
529    0,                                          /* tp_base */
530    0,                                          /* tp_dict */
531    (descrgetfunc)member_get,                   /* tp_descr_get */
532    (descrsetfunc)member_set,                   /* tp_descr_set */
533};
534
535PyTypeObject PyGetSetDescr_Type = {
536    PyVarObject_HEAD_INIT(&PyType_Type, 0)
537    "getset_descriptor",
538    sizeof(PyGetSetDescrObject),
539    0,
540    (destructor)descr_dealloc,                  /* tp_dealloc */
541    0,                                          /* tp_print */
542    0,                                          /* tp_getattr */
543    0,                                          /* tp_setattr */
544    0,                                          /* tp_compare */
545    (reprfunc)getset_repr,                      /* tp_repr */
546    0,                                          /* tp_as_number */
547    0,                                          /* tp_as_sequence */
548    0,                                          /* tp_as_mapping */
549    0,                                          /* tp_hash */
550    0,                                          /* tp_call */
551    0,                                          /* tp_str */
552    PyObject_GenericGetAttr,                    /* tp_getattro */
553    0,                                          /* tp_setattro */
554    0,                                          /* tp_as_buffer */
555    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
556    0,                                          /* tp_doc */
557    descr_traverse,                             /* tp_traverse */
558    0,                                          /* tp_clear */
559    0,                                          /* tp_richcompare */
560    0,                                          /* tp_weaklistoffset */
561    0,                                          /* tp_iter */
562    0,                                          /* tp_iternext */
563    0,                                          /* tp_methods */
564    descr_members,                              /* tp_members */
565    getset_getset,                              /* tp_getset */
566    0,                                          /* tp_base */
567    0,                                          /* tp_dict */
568    (descrgetfunc)getset_get,                   /* tp_descr_get */
569    (descrsetfunc)getset_set,                   /* tp_descr_set */
570};
571
572PyTypeObject PyWrapperDescr_Type = {
573    PyVarObject_HEAD_INIT(&PyType_Type, 0)
574    "wrapper_descriptor",
575    sizeof(PyWrapperDescrObject),
576    0,
577    (destructor)descr_dealloc,                  /* tp_dealloc */
578    0,                                          /* tp_print */
579    0,                                          /* tp_getattr */
580    0,                                          /* tp_setattr */
581    0,                                          /* tp_compare */
582    (reprfunc)wrapperdescr_repr,                /* tp_repr */
583    0,                                          /* tp_as_number */
584    0,                                          /* tp_as_sequence */
585    0,                                          /* tp_as_mapping */
586    0,                                          /* tp_hash */
587    (ternaryfunc)wrapperdescr_call,             /* tp_call */
588    0,                                          /* tp_str */
589    PyObject_GenericGetAttr,                    /* tp_getattro */
590    0,                                          /* tp_setattro */
591    0,                                          /* tp_as_buffer */
592    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
593    0,                                          /* tp_doc */
594    descr_traverse,                             /* tp_traverse */
595    0,                                          /* tp_clear */
596    0,                                          /* tp_richcompare */
597    0,                                          /* tp_weaklistoffset */
598    0,                                          /* tp_iter */
599    0,                                          /* tp_iternext */
600    0,                                          /* tp_methods */
601    descr_members,                              /* tp_members */
602    wrapperdescr_getset,                        /* tp_getset */
603    0,                                          /* tp_base */
604    0,                                          /* tp_dict */
605    (descrgetfunc)wrapperdescr_get,             /* tp_descr_get */
606    0,                                          /* tp_descr_set */
607};
608
609static PyDescrObject *
610descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)
611{
612    PyDescrObject *descr;
613
614    descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);
615    if (descr != NULL) {
616        Py_XINCREF(type);
617        descr->d_type = type;
618        descr->d_name = PyString_InternFromString(name);
619        if (descr->d_name == NULL) {
620            Py_DECREF(descr);
621            descr = NULL;
622        }
623    }
624    return descr;
625}
626
627PyObject *
628PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
629{
630    PyMethodDescrObject *descr;
631
632    descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
633                                             type, method->ml_name);
634    if (descr != NULL)
635        descr->d_method = method;
636    return (PyObject *)descr;
637}
638
639PyObject *
640PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)
641{
642    PyMethodDescrObject *descr;
643
644    descr = (PyMethodDescrObject *)descr_new(&PyClassMethodDescr_Type,
645                                             type, method->ml_name);
646    if (descr != NULL)
647        descr->d_method = method;
648    return (PyObject *)descr;
649}
650
651PyObject *
652PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member)
653{
654    PyMemberDescrObject *descr;
655
656    descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,
657                                             type, member->name);
658    if (descr != NULL)
659        descr->d_member = member;
660    return (PyObject *)descr;
661}
662
663PyObject *
664PyDescr_NewGetSet(PyTypeObject *type, PyGetSetDef *getset)
665{
666    PyGetSetDescrObject *descr;
667
668    descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
669                                             type, getset->name);
670    if (descr != NULL)
671        descr->d_getset = getset;
672    return (PyObject *)descr;
673}
674
675PyObject *
676PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
677{
678    PyWrapperDescrObject *descr;
679
680    descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
681                                             type, base->name);
682    if (descr != NULL) {
683        descr->d_base = base;
684        descr->d_wrapped = wrapped;
685    }
686    return (PyObject *)descr;
687}
688
689
690/* --- Readonly proxy for dictionaries (actually any mapping) --- */
691
692/* This has no reason to be in this file except that adding new files is a
693   bit of a pain */
694
695typedef struct {
696    PyObject_HEAD
697    PyObject *dict;
698} proxyobject;
699
700static Py_ssize_t
701proxy_len(proxyobject *pp)
702{
703    return PyObject_Size(pp->dict);
704}
705
706static PyObject *
707proxy_getitem(proxyobject *pp, PyObject *key)
708{
709    return PyObject_GetItem(pp->dict, key);
710}
711
712static PyMappingMethods proxy_as_mapping = {
713    (lenfunc)proxy_len,                         /* mp_length */
714    (binaryfunc)proxy_getitem,                  /* mp_subscript */
715    0,                                          /* mp_ass_subscript */
716};
717
718static int
719proxy_contains(proxyobject *pp, PyObject *key)
720{
721    return PyDict_Contains(pp->dict, key);
722}
723
724static PySequenceMethods proxy_as_sequence = {
725    0,                                          /* sq_length */
726    0,                                          /* sq_concat */
727    0,                                          /* sq_repeat */
728    0,                                          /* sq_item */
729    0,                                          /* sq_slice */
730    0,                                          /* sq_ass_item */
731    0,                                          /* sq_ass_slice */
732    (objobjproc)proxy_contains,                 /* sq_contains */
733    0,                                          /* sq_inplace_concat */
734    0,                                          /* sq_inplace_repeat */
735};
736
737static PyObject *
738proxy_has_key(proxyobject *pp, PyObject *key)
739{
740    int res = PyDict_Contains(pp->dict, key);
741    if (res < 0)
742        return NULL;
743    return PyBool_FromLong(res);
744}
745
746static PyObject *
747proxy_get(proxyobject *pp, PyObject *args)
748{
749    PyObject *key, *def = Py_None;
750
751    if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def))
752        return NULL;
753    return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
754}
755
756static PyObject *
757proxy_keys(proxyobject *pp)
758{
759    return PyMapping_Keys(pp->dict);
760}
761
762static PyObject *
763proxy_values(proxyobject *pp)
764{
765    return PyMapping_Values(pp->dict);
766}
767
768static PyObject *
769proxy_items(proxyobject *pp)
770{
771    return PyMapping_Items(pp->dict);
772}
773
774static PyObject *
775proxy_iterkeys(proxyobject *pp)
776{
777    return PyObject_CallMethod(pp->dict, "iterkeys", NULL);
778}
779
780static PyObject *
781proxy_itervalues(proxyobject *pp)
782{
783    return PyObject_CallMethod(pp->dict, "itervalues", NULL);
784}
785
786static PyObject *
787proxy_iteritems(proxyobject *pp)
788{
789    return PyObject_CallMethod(pp->dict, "iteritems", NULL);
790}
791static PyObject *
792proxy_copy(proxyobject *pp)
793{
794    return PyObject_CallMethod(pp->dict, "copy", NULL);
795}
796
797static PyMethodDef proxy_methods[] = {
798    {"has_key",   (PyCFunction)proxy_has_key,    METH_O,
799     PyDoc_STR("D.has_key(k) -> True if D has a key k, else False")},
800    {"get",       (PyCFunction)proxy_get,        METH_VARARGS,
801     PyDoc_STR("D.get(k[,d]) -> D[k] if D.has_key(k), else d."
802                                    "  d defaults to None.")},
803    {"keys",      (PyCFunction)proxy_keys,       METH_NOARGS,
804     PyDoc_STR("D.keys() -> list of D's keys")},
805    {"values",    (PyCFunction)proxy_values,     METH_NOARGS,
806     PyDoc_STR("D.values() -> list of D's values")},
807    {"items",     (PyCFunction)proxy_items,      METH_NOARGS,
808     PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")},
809    {"iterkeys",  (PyCFunction)proxy_iterkeys,   METH_NOARGS,
810     PyDoc_STR("D.iterkeys() -> an iterator over the keys of D")},
811    {"itervalues",(PyCFunction)proxy_itervalues, METH_NOARGS,
812     PyDoc_STR("D.itervalues() -> an iterator over the values of D")},
813    {"iteritems", (PyCFunction)proxy_iteritems,  METH_NOARGS,
814     PyDoc_STR("D.iteritems() ->"
815               " an iterator over the (key, value) items of D")},
816    {"copy",      (PyCFunction)proxy_copy,       METH_NOARGS,
817     PyDoc_STR("D.copy() -> a shallow copy of D")},
818    {0}
819};
820
821static void
822proxy_dealloc(proxyobject *pp)
823{
824    _PyObject_GC_UNTRACK(pp);
825    Py_DECREF(pp->dict);
826    PyObject_GC_Del(pp);
827}
828
829static PyObject *
830proxy_getiter(proxyobject *pp)
831{
832    return PyObject_GetIter(pp->dict);
833}
834
835static PyObject *
836proxy_str(proxyobject *pp)
837{
838    return PyObject_Str(pp->dict);
839}
840
841static PyObject *
842proxy_repr(proxyobject *pp)
843{
844    PyObject *dictrepr;
845    PyObject *result;
846
847    dictrepr = PyObject_Repr(pp->dict);
848    if (dictrepr == NULL)
849        return NULL;
850    result = PyString_FromFormat("dict_proxy(%s)", PyString_AS_STRING(dictrepr));
851    Py_DECREF(dictrepr);
852    return result;
853}
854
855static int
856proxy_traverse(PyObject *self, visitproc visit, void *arg)
857{
858    proxyobject *pp = (proxyobject *)self;
859    Py_VISIT(pp->dict);
860    return 0;
861}
862
863static int
864proxy_compare(proxyobject *v, PyObject *w)
865{
866    return PyObject_Compare(v->dict, w);
867}
868
869static PyObject *
870proxy_richcompare(proxyobject *v, PyObject *w, int op)
871{
872    return PyObject_RichCompare(v->dict, w, op);
873}
874
875PyTypeObject PyDictProxy_Type = {
876    PyVarObject_HEAD_INIT(&PyType_Type, 0)
877    "dictproxy",                                /* tp_name */
878    sizeof(proxyobject),                        /* tp_basicsize */
879    0,                                          /* tp_itemsize */
880    /* methods */
881    (destructor)proxy_dealloc,                  /* tp_dealloc */
882    0,                                          /* tp_print */
883    0,                                          /* tp_getattr */
884    0,                                          /* tp_setattr */
885    (cmpfunc)proxy_compare,                     /* tp_compare */
886    (reprfunc)proxy_repr,                       /* tp_repr */
887    0,                                          /* tp_as_number */
888    &proxy_as_sequence,                         /* tp_as_sequence */
889    &proxy_as_mapping,                          /* tp_as_mapping */
890    0,                                          /* tp_hash */
891    0,                                          /* tp_call */
892    (reprfunc)proxy_str,                        /* tp_str */
893    PyObject_GenericGetAttr,                    /* tp_getattro */
894    0,                                          /* tp_setattro */
895    0,                                          /* tp_as_buffer */
896    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
897    0,                                          /* tp_doc */
898    proxy_traverse,                             /* tp_traverse */
899    0,                                          /* tp_clear */
900    (richcmpfunc)proxy_richcompare,             /* tp_richcompare */
901    0,                                          /* tp_weaklistoffset */
902    (getiterfunc)proxy_getiter,                 /* tp_iter */
903    0,                                          /* tp_iternext */
904    proxy_methods,                              /* tp_methods */
905    0,                                          /* tp_members */
906    0,                                          /* tp_getset */
907    0,                                          /* tp_base */
908    0,                                          /* tp_dict */
909    0,                                          /* tp_descr_get */
910    0,                                          /* tp_descr_set */
911};
912
913PyObject *
914PyDictProxy_New(PyObject *dict)
915{
916    proxyobject *pp;
917
918    pp = PyObject_GC_New(proxyobject, &PyDictProxy_Type);
919    if (pp != NULL) {
920        Py_INCREF(dict);
921        pp->dict = dict;
922        _PyObject_GC_TRACK(pp);
923    }
924    return (PyObject *)pp;
925}
926
927
928/* --- Wrapper object for "slot" methods --- */
929
930/* This has no reason to be in this file except that adding new files is a
931   bit of a pain */
932
933typedef struct {
934    PyObject_HEAD
935    PyWrapperDescrObject *descr;
936    PyObject *self;
937} wrapperobject;
938
939static void
940wrapper_dealloc(wrapperobject *wp)
941{
942    PyObject_GC_UnTrack(wp);
943    Py_TRASHCAN_SAFE_BEGIN(wp)
944    Py_XDECREF(wp->descr);
945    Py_XDECREF(wp->self);
946    PyObject_GC_Del(wp);
947    Py_TRASHCAN_SAFE_END(wp)
948}
949
950static int
951wrapper_compare(wrapperobject *a, wrapperobject *b)
952{
953    if (a->descr == b->descr)
954        return PyObject_Compare(a->self, b->self);
955    else
956        return (a->descr < b->descr) ? -1 : 1;
957}
958
959static long
960wrapper_hash(wrapperobject *wp)
961{
962    int x, y;
963    x = _Py_HashPointer(wp->descr);
964    if (x == -1)
965        return -1;
966    y = PyObject_Hash(wp->self);
967    if (y == -1)
968        return -1;
969    x = x ^ y;
970    if (x == -1)
971        x = -2;
972    return x;
973}
974
975static PyObject *
976wrapper_repr(wrapperobject *wp)
977{
978    return PyString_FromFormat("<method-wrapper '%s' of %s object at %p>",
979                               wp->descr->d_base->name,
980                               wp->self->ob_type->tp_name,
981                               wp->self);
982}
983
984static PyMemberDef wrapper_members[] = {
985    {"__self__", T_OBJECT, offsetof(wrapperobject, self), READONLY},
986    {0}
987};
988
989static PyObject *
990wrapper_objclass(wrapperobject *wp)
991{
992    PyObject *c = (PyObject *)wp->descr->d_type;
993
994    Py_INCREF(c);
995    return c;
996}
997
998static PyObject *
999wrapper_name(wrapperobject *wp)
1000{
1001    char *s = wp->descr->d_base->name;
1002
1003    return PyString_FromString(s);
1004}
1005
1006static PyObject *
1007wrapper_doc(wrapperobject *wp)
1008{
1009    char *s = wp->descr->d_base->doc;
1010
1011    if (s == NULL) {
1012        Py_INCREF(Py_None);
1013        return Py_None;
1014    }
1015    else {
1016        return PyString_FromString(s);
1017    }
1018}
1019
1020static PyGetSetDef wrapper_getsets[] = {
1021    {"__objclass__", (getter)wrapper_objclass},
1022    {"__name__", (getter)wrapper_name},
1023    {"__doc__", (getter)wrapper_doc},
1024    {0}
1025};
1026
1027static PyObject *
1028wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
1029{
1030    wrapperfunc wrapper = wp->descr->d_base->wrapper;
1031    PyObject *self = wp->self;
1032
1033    if (wp->descr->d_base->flags & PyWrapperFlag_KEYWORDS) {
1034        wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper;
1035        return (*wk)(self, args, wp->descr->d_wrapped, kwds);
1036    }
1037
1038    if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) {
1039        PyErr_Format(PyExc_TypeError,
1040                     "wrapper %s doesn't take keyword arguments",
1041                     wp->descr->d_base->name);
1042        return NULL;
1043    }
1044    return (*wrapper)(self, args, wp->descr->d_wrapped);
1045}
1046
1047static int
1048wrapper_traverse(PyObject *self, visitproc visit, void *arg)
1049{
1050    wrapperobject *wp = (wrapperobject *)self;
1051    Py_VISIT(wp->descr);
1052    Py_VISIT(wp->self);
1053    return 0;
1054}
1055
1056static PyTypeObject wrappertype = {
1057    PyVarObject_HEAD_INIT(&PyType_Type, 0)
1058    "method-wrapper",                           /* tp_name */
1059    sizeof(wrapperobject),                      /* tp_basicsize */
1060    0,                                          /* tp_itemsize */
1061    /* methods */
1062    (destructor)wrapper_dealloc,                /* tp_dealloc */
1063    0,                                          /* tp_print */
1064    0,                                          /* tp_getattr */
1065    0,                                          /* tp_setattr */
1066    (cmpfunc)wrapper_compare,                   /* tp_compare */
1067    (reprfunc)wrapper_repr,                     /* tp_repr */
1068    0,                                          /* tp_as_number */
1069    0,                                          /* tp_as_sequence */
1070    0,                                          /* tp_as_mapping */
1071    (hashfunc)wrapper_hash,                     /* tp_hash */
1072    (ternaryfunc)wrapper_call,                  /* tp_call */
1073    0,                                          /* tp_str */
1074    PyObject_GenericGetAttr,                    /* tp_getattro */
1075    0,                                          /* tp_setattro */
1076    0,                                          /* tp_as_buffer */
1077    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1078    0,                                          /* tp_doc */
1079    wrapper_traverse,                           /* tp_traverse */
1080    0,                                          /* tp_clear */
1081    0,                                          /* tp_richcompare */
1082    0,                                          /* tp_weaklistoffset */
1083    0,                                          /* tp_iter */
1084    0,                                          /* tp_iternext */
1085    0,                                          /* tp_methods */
1086    wrapper_members,                            /* tp_members */
1087    wrapper_getsets,                            /* tp_getset */
1088    0,                                          /* tp_base */
1089    0,                                          /* tp_dict */
1090    0,                                          /* tp_descr_get */
1091    0,                                          /* tp_descr_set */
1092};
1093
1094PyObject *
1095PyWrapper_New(PyObject *d, PyObject *self)
1096{
1097    wrapperobject *wp;
1098    PyWrapperDescrObject *descr;
1099
1100    assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));
1101    descr = (PyWrapperDescrObject *)d;
1102    assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
1103                                    (PyObject *)(descr->d_type)));
1104
1105    wp = PyObject_GC_New(wrapperobject, &wrappertype);
1106    if (wp != NULL) {
1107        Py_INCREF(descr);
1108        wp->descr = descr;
1109        Py_INCREF(self);
1110        wp->self = self;
1111        _PyObject_GC_TRACK(wp);
1112    }
1113    return (PyObject *)wp;
1114}
1115
1116
1117/* A built-in 'property' type */
1118
1119/*
1120    class property(object):
1121
1122    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
1123        if doc is None and fget is not None and hasattr(fget, "__doc__"):
1124        doc = fget.__doc__
1125        self.__get = fget
1126        self.__set = fset
1127        self.__del = fdel
1128        self.__doc__ = doc
1129
1130    def __get__(self, inst, type=None):
1131        if inst is None:
1132        return self
1133        if self.__get is None:
1134        raise AttributeError, "unreadable attribute"
1135        return self.__get(inst)
1136
1137    def __set__(self, inst, value):
1138        if self.__set is None:
1139        raise AttributeError, "can't set attribute"
1140        return self.__set(inst, value)
1141
1142    def __delete__(self, inst):
1143        if self.__del is None:
1144        raise AttributeError, "can't delete attribute"
1145        return self.__del(inst)
1146
1147*/
1148
1149typedef struct {
1150    PyObject_HEAD
1151    PyObject *prop_get;
1152    PyObject *prop_set;
1153    PyObject *prop_del;
1154    PyObject *prop_doc;
1155    int getter_doc;
1156} propertyobject;
1157
1158static PyObject * property_copy(PyObject *, PyObject *, PyObject *,
1159                                  PyObject *);
1160
1161static PyMemberDef property_members[] = {
1162    {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY},
1163    {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY},
1164    {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY},
1165    {"__doc__",  T_OBJECT, offsetof(propertyobject, prop_doc), READONLY},
1166    {0}
1167};
1168
1169
1170PyDoc_STRVAR(getter_doc,
1171             "Descriptor to change the getter on a property.");
1172
1173static PyObject *
1174property_getter(PyObject *self, PyObject *getter)
1175{
1176    return property_copy(self, getter, NULL, NULL);
1177}
1178
1179
1180PyDoc_STRVAR(setter_doc,
1181             "Descriptor to change the setter on a property.");
1182
1183static PyObject *
1184property_setter(PyObject *self, PyObject *setter)
1185{
1186    return property_copy(self, NULL, setter, NULL);
1187}
1188
1189
1190PyDoc_STRVAR(deleter_doc,
1191             "Descriptor to change the deleter on a property.");
1192
1193static PyObject *
1194property_deleter(PyObject *self, PyObject *deleter)
1195{
1196    return property_copy(self, NULL, NULL, deleter);
1197}
1198
1199
1200static PyMethodDef property_methods[] = {
1201    {"getter", property_getter, METH_O, getter_doc},
1202    {"setter", property_setter, METH_O, setter_doc},
1203    {"deleter", property_deleter, METH_O, deleter_doc},
1204    {0}
1205};
1206
1207
1208static void
1209property_dealloc(PyObject *self)
1210{
1211    propertyobject *gs = (propertyobject *)self;
1212
1213    _PyObject_GC_UNTRACK(self);
1214    Py_XDECREF(gs->prop_get);
1215    Py_XDECREF(gs->prop_set);
1216    Py_XDECREF(gs->prop_del);
1217    Py_XDECREF(gs->prop_doc);
1218    self->ob_type->tp_free(self);
1219}
1220
1221static PyObject *
1222property_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1223{
1224    propertyobject *gs = (propertyobject *)self;
1225
1226    if (obj == NULL || obj == Py_None) {
1227        Py_INCREF(self);
1228        return self;
1229    }
1230    if (gs->prop_get == NULL) {
1231        PyErr_SetString(PyExc_AttributeError, "unreadable attribute");
1232        return NULL;
1233    }
1234    return PyObject_CallFunction(gs->prop_get, "(O)", obj);
1235}
1236
1237static int
1238property_descr_set(PyObject *self, PyObject *obj, PyObject *value)
1239{
1240    propertyobject *gs = (propertyobject *)self;
1241    PyObject *func, *res;
1242
1243    if (value == NULL)
1244        func = gs->prop_del;
1245    else
1246        func = gs->prop_set;
1247    if (func == NULL) {
1248        PyErr_SetString(PyExc_AttributeError,
1249                        value == NULL ?
1250                        "can't delete attribute" :
1251                "can't set attribute");
1252        return -1;
1253    }
1254    if (value == NULL)
1255        res = PyObject_CallFunction(func, "(O)", obj);
1256    else
1257        res = PyObject_CallFunction(func, "(OO)", obj, value);
1258    if (res == NULL)
1259        return -1;
1260    Py_DECREF(res);
1261    return 0;
1262}
1263
1264static PyObject *
1265property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *del)
1266{
1267    propertyobject *pold = (propertyobject *)old;
1268    PyObject *new, *type, *doc;
1269
1270    type = PyObject_Type(old);
1271    if (type == NULL)
1272        return NULL;
1273
1274    if (get == NULL || get == Py_None) {
1275        Py_XDECREF(get);
1276        get = pold->prop_get ? pold->prop_get : Py_None;
1277    }
1278    if (set == NULL || set == Py_None) {
1279        Py_XDECREF(set);
1280        set = pold->prop_set ? pold->prop_set : Py_None;
1281    }
1282    if (del == NULL || del == Py_None) {
1283        Py_XDECREF(del);
1284        del = pold->prop_del ? pold->prop_del : Py_None;
1285    }
1286    if (pold->getter_doc && get != Py_None) {
1287        /* make _init use __doc__ from getter */
1288        doc = Py_None;
1289    }
1290    else {
1291        doc = pold->prop_doc ? pold->prop_doc : Py_None;
1292    }
1293
1294    new =  PyObject_CallFunction(type, "OOOO", get, set, del, doc);
1295    Py_DECREF(type);
1296    if (new == NULL)
1297        return NULL;
1298    return new;
1299}
1300
1301static int
1302property_init(PyObject *self, PyObject *args, PyObject *kwds)
1303{
1304    PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL;
1305    static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0};
1306    propertyobject *prop = (propertyobject *)self;
1307
1308    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property",
1309                                     kwlist, &get, &set, &del, &doc))
1310        return -1;
1311
1312    if (get == Py_None)
1313        get = NULL;
1314    if (set == Py_None)
1315        set = NULL;
1316    if (del == Py_None)
1317        del = NULL;
1318
1319    Py_XINCREF(get);
1320    Py_XINCREF(set);
1321    Py_XINCREF(del);
1322    Py_XINCREF(doc);
1323
1324    prop->prop_get = get;
1325    prop->prop_set = set;
1326    prop->prop_del = del;
1327    prop->prop_doc = doc;
1328    prop->getter_doc = 0;
1329
1330    /* if no docstring given and the getter has one, use that one */
1331    if ((doc == NULL || doc == Py_None) && get != NULL) {
1332        PyObject *get_doc = PyObject_GetAttrString(get, "__doc__");
1333        if (get_doc) {
1334            if (Py_TYPE(self) == &PyProperty_Type) {
1335                Py_XDECREF(prop->prop_doc);
1336                prop->prop_doc = get_doc;
1337            }
1338            else {
1339                /* If this is a property subclass, put __doc__
1340                in dict of the subclass instance instead,
1341                otherwise it gets shadowed by __doc__ in the
1342                class's dict. */
1343                int err = PyObject_SetAttrString(self, "__doc__", get_doc);
1344                Py_DECREF(get_doc);
1345                if (err < 0)
1346                    return -1;
1347            }
1348            prop->getter_doc = 1;
1349        }
1350        else if (PyErr_ExceptionMatches(PyExc_Exception)) {
1351            PyErr_Clear();
1352        }
1353        else {
1354            return -1;
1355        }
1356    }
1357
1358    return 0;
1359}
1360
1361PyDoc_STRVAR(property_doc,
1362"property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n"
1363"\n"
1364"fget is a function to be used for getting an attribute value, and likewise\n"
1365"fset is a function for setting, and fdel a function for del'ing, an\n"
1366"attribute.  Typical use is to define a managed attribute x:\n\n"
1367"class C(object):\n"
1368"    def getx(self): return self._x\n"
1369"    def setx(self, value): self._x = value\n"
1370"    def delx(self): del self._x\n"
1371"    x = property(getx, setx, delx, \"I'm the 'x' property.\")\n"
1372"\n"
1373"Decorators make defining new properties or modifying existing ones easy:\n\n"
1374"class C(object):\n"
1375"    @property\n"
1376"    def x(self):\n"
1377"        \"I am the 'x' property.\"\n"
1378"        return self._x\n"
1379"    @x.setter\n"
1380"    def x(self, value):\n"
1381"        self._x = value\n"
1382"    @x.deleter\n"
1383"    def x(self):\n"
1384"        del self._x\n"
1385);
1386
1387static int
1388property_traverse(PyObject *self, visitproc visit, void *arg)
1389{
1390    propertyobject *pp = (propertyobject *)self;
1391    Py_VISIT(pp->prop_get);
1392    Py_VISIT(pp->prop_set);
1393    Py_VISIT(pp->prop_del);
1394    Py_VISIT(pp->prop_doc);
1395    return 0;
1396}
1397
1398PyTypeObject PyProperty_Type = {
1399    PyVarObject_HEAD_INIT(&PyType_Type, 0)
1400    "property",                                 /* tp_name */
1401    sizeof(propertyobject),                     /* tp_basicsize */
1402    0,                                          /* tp_itemsize */
1403    /* methods */
1404    property_dealloc,                           /* tp_dealloc */
1405    0,                                          /* tp_print */
1406    0,                                          /* tp_getattr */
1407    0,                                          /* tp_setattr */
1408    0,                                          /* tp_compare */
1409    0,                                          /* tp_repr */
1410    0,                                          /* tp_as_number */
1411    0,                                          /* tp_as_sequence */
1412    0,                                          /* tp_as_mapping */
1413    0,                                          /* tp_hash */
1414    0,                                          /* tp_call */
1415    0,                                          /* tp_str */
1416    PyObject_GenericGetAttr,                    /* tp_getattro */
1417    0,                                          /* tp_setattro */
1418    0,                                          /* tp_as_buffer */
1419    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1420        Py_TPFLAGS_BASETYPE,                    /* tp_flags */
1421    property_doc,                               /* tp_doc */
1422    property_traverse,                          /* tp_traverse */
1423    0,                                          /* tp_clear */
1424    0,                                          /* tp_richcompare */
1425    0,                                          /* tp_weaklistoffset */
1426    0,                                          /* tp_iter */
1427    0,                                          /* tp_iternext */
1428    property_methods,                           /* tp_methods */
1429    property_members,                           /* tp_members */
1430    0,                                          /* tp_getset */
1431    0,                                          /* tp_base */
1432    0,                                          /* tp_dict */
1433    property_descr_get,                         /* tp_descr_get */
1434    property_descr_set,                         /* tp_descr_set */
1435    0,                                          /* tp_dictoffset */
1436    property_init,                              /* tp_init */
1437    PyType_GenericAlloc,                        /* tp_alloc */
1438    PyType_GenericNew,                          /* tp_new */
1439    PyObject_GC_Del,                            /* tp_free */
1440};
1441