1 /* Descriptors -- a new, flexible way to describe attributes */
4 #include "structmember.h" /* Why is this not included in Python.h? */
7 descr_dealloc(PyDescrObject
*descr
)
9 _PyObject_GC_UNTRACK(descr
);
10 Py_XDECREF(descr
->d_type
);
11 Py_XDECREF(descr
->d_name
);
12 PyObject_GC_Del(descr
);
16 descr_name(PyDescrObject
*descr
)
18 if (descr
->d_name
!= NULL
&& PyString_Check(descr
->d_name
))
19 return PyString_AS_STRING(descr
->d_name
);
25 descr_repr(PyDescrObject
*descr
, char *format
)
27 return PyString_FromFormat(format
, descr_name(descr
),
28 descr
->d_type
->tp_name
);
32 method_repr(PyMethodDescrObject
*descr
)
34 return descr_repr((PyDescrObject
*)descr
,
35 "<method '%s' of '%s' objects>");
39 member_repr(PyMemberDescrObject
*descr
)
41 return descr_repr((PyDescrObject
*)descr
,
42 "<member '%s' of '%s' objects>");
46 getset_repr(PyGetSetDescrObject
*descr
)
48 return descr_repr((PyDescrObject
*)descr
,
49 "<attribute '%s' of '%s' objects>");
53 wrapper_repr(PyWrapperDescrObject
*descr
)
55 return descr_repr((PyDescrObject
*)descr
,
56 "<slot wrapper '%s' of '%s' objects>");
60 descr_check(PyDescrObject
*descr
, PyObject
*obj
, PyTypeObject
*type
,
63 if (obj
== NULL
|| (obj
== Py_None
&& type
!= Py_None
->ob_type
)) {
65 *pres
= (PyObject
*)descr
;
68 if (!PyObject_TypeCheck(obj
, descr
->d_type
)) {
69 PyErr_Format(PyExc_TypeError
,
70 "descriptor '%s' for '%s' objects "
71 "doesn't apply to '%s' object",
72 descr_name((PyDescrObject
*)descr
),
73 descr
->d_type
->tp_name
,
74 obj
->ob_type
->tp_name
);
82 classmethod_get(PyMethodDescrObject
*descr
, PyObject
*obj
,
85 return PyCFunction_New(descr
->d_method
, (PyObject
*)type
);
89 method_get(PyMethodDescrObject
*descr
, PyObject
*obj
, PyTypeObject
*type
)
93 if (descr_check((PyDescrObject
*)descr
, obj
, type
, &res
))
95 return PyCFunction_New(descr
->d_method
, obj
);
99 member_get(PyMemberDescrObject
*descr
, PyObject
*obj
, PyTypeObject
*type
)
103 if (descr_check((PyDescrObject
*)descr
, obj
, type
, &res
))
105 return PyMember_GetOne((char *)obj
, descr
->d_member
);
109 getset_get(PyGetSetDescrObject
*descr
, PyObject
*obj
, PyTypeObject
*type
)
113 if (descr_check((PyDescrObject
*)descr
, obj
, type
, &res
))
115 if (descr
->d_getset
->get
!= NULL
)
116 return descr
->d_getset
->get(obj
, descr
->d_getset
->closure
);
117 PyErr_Format(PyExc_TypeError
,
118 "attribute '%.300s' of '%.100s' objects is not readable",
119 descr_name((PyDescrObject
*)descr
),
120 descr
->d_type
->tp_name
);
125 wrapper_get(PyWrapperDescrObject
*descr
, PyObject
*obj
, PyTypeObject
*type
)
129 if (descr_check((PyDescrObject
*)descr
, obj
, type
, &res
))
131 return PyWrapper_New((PyObject
*)descr
, obj
);
135 descr_setcheck(PyDescrObject
*descr
, PyObject
*obj
, PyObject
*value
,
139 if (!PyObject_IsInstance(obj
, (PyObject
*)(descr
->d_type
))) {
140 PyErr_Format(PyExc_TypeError
,
141 "descriptor '%.200s' for '%.100s' objects "
142 "doesn't apply to '%.100s' object",
144 descr
->d_type
->tp_name
,
145 obj
->ob_type
->tp_name
);
153 member_set(PyMemberDescrObject
*descr
, PyObject
*obj
, PyObject
*value
)
157 if (descr_setcheck((PyDescrObject
*)descr
, obj
, value
, &res
))
159 return PyMember_SetOne((char *)obj
, descr
->d_member
, value
);
163 getset_set(PyGetSetDescrObject
*descr
, PyObject
*obj
, PyObject
*value
)
167 if (descr_setcheck((PyDescrObject
*)descr
, obj
, value
, &res
))
169 if (descr
->d_getset
->set
!= NULL
)
170 return descr
->d_getset
->set(obj
, value
,
171 descr
->d_getset
->closure
);
172 PyErr_Format(PyExc_TypeError
,
173 "attribute '%.300s' of '%.100s' objects is not writable",
174 descr_name((PyDescrObject
*)descr
),
175 descr
->d_type
->tp_name
);
180 methoddescr_call(PyMethodDescrObject
*descr
, PyObject
*args
, PyObject
*kwds
)
183 PyObject
*self
, *func
, *result
;
185 /* Make sure that the first argument is acceptable as 'self' */
186 assert(PyTuple_Check(args
));
187 argc
= PyTuple_GET_SIZE(args
);
189 PyErr_Format(PyExc_TypeError
,
190 "descriptor '%.300s' of '%.100s' "
191 "object needs an argument",
192 descr_name((PyDescrObject
*)descr
),
193 descr
->d_type
->tp_name
);
196 self
= PyTuple_GET_ITEM(args
, 0);
197 if (!PyObject_IsInstance(self
, (PyObject
*)(descr
->d_type
))) {
198 PyErr_Format(PyExc_TypeError
,
199 "descriptor '%.200s' "
200 "requires a '%.100s' object "
201 "but received a '%.100s'",
202 descr_name((PyDescrObject
*)descr
),
203 descr
->d_type
->tp_name
,
204 self
->ob_type
->tp_name
);
208 func
= PyCFunction_New(descr
->d_method
, self
);
211 args
= PyTuple_GetSlice(args
, 1, argc
);
216 result
= PyEval_CallObjectWithKeywords(func
, args
, kwds
);
223 classmethoddescr_call(PyMethodDescrObject
*descr
, PyObject
*args
,
226 PyObject
*func
, *result
;
228 func
= PyCFunction_New(descr
->d_method
, (PyObject
*)descr
->d_type
);
232 result
= PyEval_CallObjectWithKeywords(func
, args
, kwds
);
238 wrapperdescr_call(PyWrapperDescrObject
*descr
, PyObject
*args
, PyObject
*kwds
)
241 PyObject
*self
, *func
, *result
;
243 /* Make sure that the first argument is acceptable as 'self' */
244 assert(PyTuple_Check(args
));
245 argc
= PyTuple_GET_SIZE(args
);
247 PyErr_Format(PyExc_TypeError
,
248 "descriptor '%.300s' of '%.100s' "
249 "object needs an argument",
250 descr_name((PyDescrObject
*)descr
),
251 descr
->d_type
->tp_name
);
254 self
= PyTuple_GET_ITEM(args
, 0);
255 if (!PyObject_IsInstance(self
, (PyObject
*)(descr
->d_type
))) {
256 PyErr_Format(PyExc_TypeError
,
257 "descriptor '%.200s' "
258 "requires a '%.100s' object "
259 "but received a '%.100s'",
260 descr_name((PyDescrObject
*)descr
),
261 descr
->d_type
->tp_name
,
262 self
->ob_type
->tp_name
);
266 func
= PyWrapper_New((PyObject
*)descr
, self
);
269 args
= PyTuple_GetSlice(args
, 1, argc
);
274 result
= PyEval_CallObjectWithKeywords(func
, args
, kwds
);
281 method_get_doc(PyMethodDescrObject
*descr
, void *closure
)
283 if (descr
->d_method
->ml_doc
== NULL
) {
287 return PyString_FromString(descr
->d_method
->ml_doc
);
290 static PyMemberDef descr_members
[] = {
291 {"__objclass__", T_OBJECT
, offsetof(PyDescrObject
, d_type
), READONLY
},
292 {"__name__", T_OBJECT
, offsetof(PyDescrObject
, d_name
), READONLY
},
296 static PyGetSetDef method_getset
[] = {
297 {"__doc__", (getter
)method_get_doc
},
302 member_get_doc(PyMemberDescrObject
*descr
, void *closure
)
304 if (descr
->d_member
->doc
== NULL
) {
308 return PyString_FromString(descr
->d_member
->doc
);
311 static PyGetSetDef member_getset
[] = {
312 {"__doc__", (getter
)member_get_doc
},
317 getset_get_doc(PyGetSetDescrObject
*descr
, void *closure
)
319 if (descr
->d_getset
->doc
== NULL
) {
323 return PyString_FromString(descr
->d_getset
->doc
);
326 static PyGetSetDef getset_getset
[] = {
327 {"__doc__", (getter
)getset_get_doc
},
332 wrapper_get_doc(PyWrapperDescrObject
*descr
, void *closure
)
334 if (descr
->d_base
->doc
== NULL
) {
338 return PyString_FromString(descr
->d_base
->doc
);
341 static PyGetSetDef wrapper_getset
[] = {
342 {"__doc__", (getter
)wrapper_get_doc
},
347 descr_traverse(PyObject
*self
, visitproc visit
, void *arg
)
349 PyDescrObject
*descr
= (PyDescrObject
*)self
;
353 err
= visit((PyObject
*)(descr
->d_type
), arg
);
360 static PyTypeObject PyMethodDescr_Type
= {
361 PyObject_HEAD_INIT(&PyType_Type
)
364 sizeof(PyMethodDescrObject
),
366 (destructor
)descr_dealloc
, /* tp_dealloc */
371 (reprfunc
)method_repr
, /* tp_repr */
372 0, /* tp_as_number */
373 0, /* tp_as_sequence */
374 0, /* tp_as_mapping */
376 (ternaryfunc
)methoddescr_call
, /* tp_call */
378 PyObject_GenericGetAttr
, /* tp_getattro */
380 0, /* tp_as_buffer */
381 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
383 descr_traverse
, /* tp_traverse */
385 0, /* tp_richcompare */
386 0, /* tp_weaklistoffset */
390 descr_members
, /* tp_members */
391 method_getset
, /* tp_getset */
394 (descrgetfunc
)method_get
, /* tp_descr_get */
395 0, /* tp_descr_set */
398 static PyTypeObject PyClassMethodDescr_Type
= {
399 PyObject_HEAD_INIT(&PyType_Type
)
401 "special_method_descriptor",
402 sizeof(PyMethodDescrObject
),
404 (destructor
)descr_dealloc
, /* tp_dealloc */
409 (reprfunc
)method_repr
, /* tp_repr */
410 0, /* tp_as_number */
411 0, /* tp_as_sequence */
412 0, /* tp_as_mapping */
414 (ternaryfunc
)classmethoddescr_call
, /* tp_call */
416 PyObject_GenericGetAttr
, /* tp_getattro */
418 0, /* tp_as_buffer */
419 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
421 descr_traverse
, /* tp_traverse */
423 0, /* tp_richcompare */
424 0, /* tp_weaklistoffset */
428 descr_members
, /* tp_members */
429 method_getset
, /* tp_getset */
432 (descrgetfunc
)classmethod_get
, /* tp_descr_get */
433 0, /* tp_descr_set */
436 static PyTypeObject PyMemberDescr_Type
= {
437 PyObject_HEAD_INIT(&PyType_Type
)
440 sizeof(PyMemberDescrObject
),
442 (destructor
)descr_dealloc
, /* tp_dealloc */
447 (reprfunc
)member_repr
, /* tp_repr */
448 0, /* tp_as_number */
449 0, /* tp_as_sequence */
450 0, /* tp_as_mapping */
452 (ternaryfunc
)0, /* tp_call */
454 PyObject_GenericGetAttr
, /* tp_getattro */
456 0, /* tp_as_buffer */
457 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
459 descr_traverse
, /* tp_traverse */
461 0, /* tp_richcompare */
462 0, /* tp_weaklistoffset */
466 descr_members
, /* tp_members */
467 member_getset
, /* tp_getset */
470 (descrgetfunc
)member_get
, /* tp_descr_get */
471 (descrsetfunc
)member_set
, /* tp_descr_set */
474 static PyTypeObject PyGetSetDescr_Type
= {
475 PyObject_HEAD_INIT(&PyType_Type
)
478 sizeof(PyGetSetDescrObject
),
480 (destructor
)descr_dealloc
, /* tp_dealloc */
485 (reprfunc
)getset_repr
, /* tp_repr */
486 0, /* tp_as_number */
487 0, /* tp_as_sequence */
488 0, /* tp_as_mapping */
490 (ternaryfunc
)0, /* tp_call */
492 PyObject_GenericGetAttr
, /* tp_getattro */
494 0, /* tp_as_buffer */
495 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
497 descr_traverse
, /* tp_traverse */
499 0, /* tp_richcompare */
500 0, /* tp_weaklistoffset */
504 descr_members
, /* tp_members */
505 getset_getset
, /* tp_getset */
508 (descrgetfunc
)getset_get
, /* tp_descr_get */
509 (descrsetfunc
)getset_set
, /* tp_descr_set */
512 PyTypeObject PyWrapperDescr_Type
= {
513 PyObject_HEAD_INIT(&PyType_Type
)
515 "wrapper_descriptor",
516 sizeof(PyWrapperDescrObject
),
518 (destructor
)descr_dealloc
, /* tp_dealloc */
523 (reprfunc
)wrapper_repr
, /* tp_repr */
524 0, /* tp_as_number */
525 0, /* tp_as_sequence */
526 0, /* tp_as_mapping */
528 (ternaryfunc
)wrapperdescr_call
, /* tp_call */
530 PyObject_GenericGetAttr
, /* tp_getattro */
532 0, /* tp_as_buffer */
533 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
535 descr_traverse
, /* tp_traverse */
537 0, /* tp_richcompare */
538 0, /* tp_weaklistoffset */
542 descr_members
, /* tp_members */
543 wrapper_getset
, /* tp_getset */
546 (descrgetfunc
)wrapper_get
, /* tp_descr_get */
547 0, /* tp_descr_set */
550 static PyDescrObject
*
551 descr_new(PyTypeObject
*descrtype
, PyTypeObject
*type
, char *name
)
553 PyDescrObject
*descr
;
555 descr
= (PyDescrObject
*)PyType_GenericAlloc(descrtype
, 0);
558 descr
->d_type
= type
;
559 descr
->d_name
= PyString_InternFromString(name
);
560 if (descr
->d_name
== NULL
) {
569 PyDescr_NewMethod(PyTypeObject
*type
, PyMethodDef
*method
)
571 PyMethodDescrObject
*descr
;
573 descr
= (PyMethodDescrObject
*)descr_new(&PyMethodDescr_Type
,
574 type
, method
->ml_name
);
576 descr
->d_method
= method
;
577 return (PyObject
*)descr
;
581 PyDescr_NewClassMethod(PyTypeObject
*type
, PyMethodDef
*method
)
583 PyMethodDescrObject
*descr
;
585 descr
= (PyMethodDescrObject
*)descr_new(&PyClassMethodDescr_Type
,
586 type
, method
->ml_name
);
588 descr
->d_method
= method
;
589 return (PyObject
*)descr
;
593 PyDescr_NewMember(PyTypeObject
*type
, PyMemberDef
*member
)
595 PyMemberDescrObject
*descr
;
597 descr
= (PyMemberDescrObject
*)descr_new(&PyMemberDescr_Type
,
600 descr
->d_member
= member
;
601 return (PyObject
*)descr
;
605 PyDescr_NewGetSet(PyTypeObject
*type
, PyGetSetDef
*getset
)
607 PyGetSetDescrObject
*descr
;
609 descr
= (PyGetSetDescrObject
*)descr_new(&PyGetSetDescr_Type
,
612 descr
->d_getset
= getset
;
613 return (PyObject
*)descr
;
617 PyDescr_NewWrapper(PyTypeObject
*type
, struct wrapperbase
*base
, void *wrapped
)
619 PyWrapperDescrObject
*descr
;
621 descr
= (PyWrapperDescrObject
*)descr_new(&PyWrapperDescr_Type
,
624 descr
->d_base
= base
;
625 descr
->d_wrapped
= wrapped
;
627 return (PyObject
*)descr
;
631 /* --- Readonly proxy for dictionaries (actually any mapping) --- */
633 /* This has no reason to be in this file except that adding new files is a
642 proxy_len(proxyobject
*pp
)
644 return PyObject_Size(pp
->dict
);
648 proxy_getitem(proxyobject
*pp
, PyObject
*key
)
650 return PyObject_GetItem(pp
->dict
, key
);
653 static PyMappingMethods proxy_as_mapping
= {
654 (inquiry
)proxy_len
, /* mp_length */
655 (binaryfunc
)proxy_getitem
, /* mp_subscript */
656 0, /* mp_ass_subscript */
660 proxy_contains(proxyobject
*pp
, PyObject
*key
)
662 return PySequence_Contains(pp
->dict
, key
);
665 static PySequenceMethods proxy_as_sequence
= {
672 0, /* sq_ass_slice */
673 (objobjproc
)proxy_contains
, /* sq_contains */
674 0, /* sq_inplace_concat */
675 0, /* sq_inplace_repeat */
679 proxy_has_key(proxyobject
*pp
, PyObject
*key
)
681 return PyInt_FromLong(PySequence_Contains(pp
->dict
, key
));
685 proxy_get(proxyobject
*pp
, PyObject
*args
)
687 PyObject
*key
, *def
= Py_None
;
689 if (!PyArg_UnpackTuple(args
, "get", 1, 2, &key
, &def
))
691 return PyObject_CallMethod(pp
->dict
, "get", "(OO)", key
, def
);
695 proxy_keys(proxyobject
*pp
)
697 return PyMapping_Keys(pp
->dict
);
701 proxy_values(proxyobject
*pp
)
703 return PyMapping_Values(pp
->dict
);
707 proxy_items(proxyobject
*pp
)
709 return PyMapping_Items(pp
->dict
);
713 proxy_iterkeys(proxyobject
*pp
)
715 return PyObject_CallMethod(pp
->dict
, "iterkeys", NULL
);
719 proxy_itervalues(proxyobject
*pp
)
721 return PyObject_CallMethod(pp
->dict
, "itervalues", NULL
);
725 proxy_iteritems(proxyobject
*pp
)
727 return PyObject_CallMethod(pp
->dict
, "iteritems", NULL
);
730 proxy_copy(proxyobject
*pp
)
732 return PyObject_CallMethod(pp
->dict
, "copy", NULL
);
735 static PyMethodDef proxy_methods
[] = {
736 {"has_key", (PyCFunction
)proxy_has_key
, METH_O
,
737 PyDoc_STR("D.has_key(k) -> 1 if D has a key k, else 0")},
738 {"get", (PyCFunction
)proxy_get
, METH_VARARGS
,
739 PyDoc_STR("D.get(k[,d]) -> D[k] if D.has_key(k), else d."
740 " d defaults to None.")},
741 {"keys", (PyCFunction
)proxy_keys
, METH_NOARGS
,
742 PyDoc_STR("D.keys() -> list of D's keys")},
743 {"values", (PyCFunction
)proxy_values
, METH_NOARGS
,
744 PyDoc_STR("D.values() -> list of D's values")},
745 {"items", (PyCFunction
)proxy_items
, METH_NOARGS
,
746 PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")},
747 {"iterkeys", (PyCFunction
)proxy_iterkeys
, METH_NOARGS
,
748 PyDoc_STR("D.iterkeys() -> an iterator over the keys of D")},
749 {"itervalues",(PyCFunction
)proxy_itervalues
, METH_NOARGS
,
750 PyDoc_STR("D.itervalues() -> an iterator over the values of D")},
751 {"iteritems", (PyCFunction
)proxy_iteritems
, METH_NOARGS
,
752 PyDoc_STR("D.iteritems() ->"
753 " an iterator over the (key, value) items of D")},
754 {"copy", (PyCFunction
)proxy_copy
, METH_NOARGS
,
755 PyDoc_STR("D.copy() -> a shallow copy of D")},
760 proxy_dealloc(proxyobject
*pp
)
762 _PyObject_GC_UNTRACK(pp
);
768 proxy_getiter(proxyobject
*pp
)
770 return PyObject_GetIter(pp
->dict
);
774 proxy_str(proxyobject
*pp
)
776 return PyObject_Str(pp
->dict
);
780 proxy_traverse(PyObject
*self
, visitproc visit
, void *arg
)
782 proxyobject
*pp
= (proxyobject
*)self
;
786 err
= visit(pp
->dict
, arg
);
794 proxy_compare(proxyobject
*v
, PyObject
*w
)
796 return PyObject_Compare(v
->dict
, w
);
800 proxy_richcompare(proxyobject
*v
, PyObject
*w
, int op
)
802 return PyObject_RichCompare(v
->dict
, w
, op
);
805 static PyTypeObject proxytype
= {
806 PyObject_HEAD_INIT(&PyType_Type
)
808 "dictproxy", /* tp_name */
809 sizeof(proxyobject
), /* tp_basicsize */
812 (destructor
)proxy_dealloc
, /* tp_dealloc */
816 (cmpfunc
)proxy_compare
, /* tp_compare */
818 0, /* tp_as_number */
819 &proxy_as_sequence
, /* tp_as_sequence */
820 &proxy_as_mapping
, /* tp_as_mapping */
823 (reprfunc
)proxy_str
, /* tp_str */
824 PyObject_GenericGetAttr
, /* tp_getattro */
826 0, /* tp_as_buffer */
827 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
829 proxy_traverse
, /* tp_traverse */
831 (richcmpfunc
)proxy_richcompare
, /* tp_richcompare */
832 0, /* tp_weaklistoffset */
833 (getiterfunc
)proxy_getiter
, /* tp_iter */
835 proxy_methods
, /* tp_methods */
840 0, /* tp_descr_get */
841 0, /* tp_descr_set */
845 PyDictProxy_New(PyObject
*dict
)
849 pp
= PyObject_GC_New(proxyobject
, &proxytype
);
853 _PyObject_GC_TRACK(pp
);
855 return (PyObject
*)pp
;
859 /* --- Wrapper object for "slot" methods --- */
861 /* This has no reason to be in this file except that adding new files is a
866 PyWrapperDescrObject
*descr
;
871 wrapper_dealloc(wrapperobject
*wp
)
873 _PyObject_GC_UNTRACK(wp
);
874 Py_XDECREF(wp
->descr
);
875 Py_XDECREF(wp
->self
);
879 static PyMethodDef wrapper_methods
[] = {
884 wrapper_name(wrapperobject
*wp
)
886 char *s
= wp
->descr
->d_base
->name
;
888 return PyString_FromString(s
);
892 wrapper_doc(wrapperobject
*wp
)
894 char *s
= wp
->descr
->d_base
->doc
;
901 return PyString_FromString(s
);
905 static PyGetSetDef wrapper_getsets
[] = {
906 {"__name__", (getter
)wrapper_name
},
907 {"__doc__", (getter
)wrapper_doc
},
912 wrapper_call(wrapperobject
*wp
, PyObject
*args
, PyObject
*kwds
)
914 wrapperfunc wrapper
= wp
->descr
->d_base
->wrapper
;
915 PyObject
*self
= wp
->self
;
917 if (wp
->descr
->d_base
->flags
& PyWrapperFlag_KEYWORDS
) {
918 wrapperfunc_kwds wk
= (wrapperfunc_kwds
)wrapper
;
919 return (*wk
)(self
, args
, wp
->descr
->d_wrapped
, kwds
);
922 if (kwds
!= NULL
&& (!PyDict_Check(kwds
) || PyDict_Size(kwds
) != 0)) {
923 PyErr_Format(PyExc_TypeError
,
924 "wrapper %s doesn't take keyword arguments",
925 wp
->descr
->d_base
->name
);
928 return (*wrapper
)(self
, args
, wp
->descr
->d_wrapped
);
932 wrapper_traverse(PyObject
*self
, visitproc visit
, void *arg
)
934 wrapperobject
*wp
= (wrapperobject
*)self
;
938 err
= visit((PyObject
*)(wp
->descr
), arg
);
943 err
= visit(wp
->self
, arg
);
950 static PyTypeObject wrappertype
= {
951 PyObject_HEAD_INIT(&PyType_Type
)
953 "method-wrapper", /* tp_name */
954 sizeof(wrapperobject
), /* tp_basicsize */
957 (destructor
)wrapper_dealloc
, /* tp_dealloc */
963 0, /* tp_as_number */
964 0, /* tp_as_sequence */
965 0, /* tp_as_mapping */
967 (ternaryfunc
)wrapper_call
, /* tp_call */
969 PyObject_GenericGetAttr
, /* tp_getattro */
971 0, /* tp_as_buffer */
972 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
974 wrapper_traverse
, /* tp_traverse */
976 0, /* tp_richcompare */
977 0, /* tp_weaklistoffset */
980 wrapper_methods
, /* tp_methods */
982 wrapper_getsets
, /* tp_getset */
985 0, /* tp_descr_get */
986 0, /* tp_descr_set */
990 PyWrapper_New(PyObject
*d
, PyObject
*self
)
993 PyWrapperDescrObject
*descr
;
995 assert(PyObject_TypeCheck(d
, &PyWrapperDescr_Type
));
996 descr
= (PyWrapperDescrObject
*)d
;
997 assert(PyObject_IsInstance(self
, (PyObject
*)(descr
->d_type
)));
999 wp
= PyObject_GC_New(wrapperobject
, &wrappertype
);
1005 _PyObject_GC_TRACK(wp
);
1007 return (PyObject
*)wp
;
1011 /* A built-in 'property' type */
1014 class property(object):
1016 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
1022 def __get__(self, inst, type=None):
1025 if self.__get is None:
1026 raise AttributeError, "unreadable attribute"
1027 return self.__get(inst)
1029 def __set__(self, inst, value):
1030 if self.__set is None:
1031 raise AttributeError, "can't set attribute"
1032 return self.__set(inst, value)
1034 def __delete__(self, inst):
1035 if self.__del is None:
1036 raise AttributeError, "can't delete attribute"
1037 return self.__del(inst)
1049 static PyMemberDef property_members
[] = {
1050 {"fget", T_OBJECT
, offsetof(propertyobject
, prop_get
), READONLY
},
1051 {"fset", T_OBJECT
, offsetof(propertyobject
, prop_set
), READONLY
},
1052 {"fdel", T_OBJECT
, offsetof(propertyobject
, prop_del
), READONLY
},
1053 {"__doc__", T_OBJECT
, offsetof(propertyobject
, prop_doc
), READONLY
},
1059 property_dealloc(PyObject
*self
)
1061 propertyobject
*gs
= (propertyobject
*)self
;
1063 _PyObject_GC_UNTRACK(self
);
1064 Py_XDECREF(gs
->prop_get
);
1065 Py_XDECREF(gs
->prop_set
);
1066 Py_XDECREF(gs
->prop_del
);
1067 Py_XDECREF(gs
->prop_doc
);
1068 self
->ob_type
->tp_free(self
);
1072 property_descr_get(PyObject
*self
, PyObject
*obj
, PyObject
*type
)
1074 propertyobject
*gs
= (propertyobject
*)self
;
1076 if (obj
== NULL
|| obj
== Py_None
) {
1080 if (gs
->prop_get
== NULL
) {
1081 PyErr_SetString(PyExc_AttributeError
, "unreadable attribute");
1084 return PyObject_CallFunction(gs
->prop_get
, "(O)", obj
);
1088 property_descr_set(PyObject
*self
, PyObject
*obj
, PyObject
*value
)
1090 propertyobject
*gs
= (propertyobject
*)self
;
1091 PyObject
*func
, *res
;
1094 func
= gs
->prop_del
;
1096 func
= gs
->prop_set
;
1098 PyErr_SetString(PyExc_AttributeError
,
1100 "can't delete attribute" :
1101 "can't set attribute");
1105 res
= PyObject_CallFunction(func
, "(O)", obj
);
1107 res
= PyObject_CallFunction(func
, "(OO)", obj
, value
);
1115 property_init(PyObject
*self
, PyObject
*args
, PyObject
*kwds
)
1117 PyObject
*get
= NULL
, *set
= NULL
, *del
= NULL
, *doc
= NULL
;
1118 static char *kwlist
[] = {"fget", "fset", "fdel", "doc", 0};
1119 propertyobject
*gs
= (propertyobject
*)self
;
1121 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "|OOOO:property",
1122 kwlist
, &get
, &set
, &del
, &doc
))
1145 PyDoc_STRVAR(property_doc
,
1146 "property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n"
1148 "fget is a function to be used for getting an attribute value, and likewise\n"
1149 "fset is a function for setting, and fdel a function for del'ing, an\n"
1150 "attribute. Typical use is to define a managed attribute x:\n"
1151 "class C(object):\n"
1152 " def getx(self): return self.__x\n"
1153 " def setx(self, value): self.__x = value\n"
1154 " def delx(self): del self.__x\n"
1155 " x = property(getx, setx, delx, \"I'm the 'x' property.\")");
1158 property_traverse(PyObject
*self
, visitproc visit
, void *arg
)
1160 propertyobject
*pp
= (propertyobject
*)self
;
1163 #define VISIT(SLOT) \
1165 err = visit((PyObject *)(pp->SLOT), arg); \
1177 PyTypeObject PyProperty_Type
= {
1178 PyObject_HEAD_INIT(&PyType_Type
)
1180 "property", /* tp_name */
1181 sizeof(propertyobject
), /* tp_basicsize */
1182 0, /* tp_itemsize */
1184 property_dealloc
, /* tp_dealloc */
1190 0, /* tp_as_number */
1191 0, /* tp_as_sequence */
1192 0, /* tp_as_mapping */
1196 PyObject_GenericGetAttr
, /* tp_getattro */
1197 0, /* tp_setattro */
1198 0, /* tp_as_buffer */
1199 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
|
1200 Py_TPFLAGS_BASETYPE
, /* tp_flags */
1201 property_doc
, /* tp_doc */
1202 property_traverse
, /* tp_traverse */
1204 0, /* tp_richcompare */
1205 0, /* tp_weaklistoffset */
1207 0, /* tp_iternext */
1209 property_members
, /* tp_members */
1213 property_descr_get
, /* tp_descr_get */
1214 property_descr_set
, /* tp_descr_set */
1215 0, /* tp_dictoffset */
1216 property_init
, /* tp_init */
1217 PyType_GenericAlloc
, /* tp_alloc */
1218 PyType_GenericNew
, /* tp_new */
1219 PyObject_GC_Del
, /* tp_free */