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
, PyObject
**pres
)
64 *pres
= (PyObject
*)descr
;
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
);
81 classmethod_get(PyMethodDescrObject
*descr
, PyObject
*obj
, PyObject
*type
)
83 /* Ensure a valid type. Class methods ignore obj. */
86 type
= (PyObject
*)obj
->ob_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
);
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
);
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
);
115 return PyCFunction_New(descr
->d_method
, type
);
119 method_get(PyMethodDescrObject
*descr
, PyObject
*obj
, PyObject
*type
)
123 if (descr_check((PyDescrObject
*)descr
, obj
, &res
))
125 return PyCFunction_New(descr
->d_method
, obj
);
129 member_get(PyMemberDescrObject
*descr
, PyObject
*obj
, PyObject
*type
)
133 if (descr_check((PyDescrObject
*)descr
, obj
, &res
))
135 return PyMember_GetOne((char *)obj
, descr
->d_member
);
139 getset_get(PyGetSetDescrObject
*descr
, PyObject
*obj
, PyObject
*type
)
143 if (descr_check((PyDescrObject
*)descr
, obj
, &res
))
145 if (descr
->d_getset
->get
!= NULL
)
146 return descr
->d_getset
->get(obj
, descr
->d_getset
->closure
);
147 PyErr_Format(PyExc_TypeError
,
148 "attribute '%.300s' of '%.100s' objects is not readable",
149 descr_name((PyDescrObject
*)descr
),
150 descr
->d_type
->tp_name
);
155 wrapper_get(PyWrapperDescrObject
*descr
, PyObject
*obj
, PyObject
*type
)
159 if (descr_check((PyDescrObject
*)descr
, obj
, &res
))
161 return PyWrapper_New((PyObject
*)descr
, obj
);
165 descr_setcheck(PyDescrObject
*descr
, PyObject
*obj
, PyObject
*value
,
169 if (!PyObject_IsInstance(obj
, (PyObject
*)(descr
->d_type
))) {
170 PyErr_Format(PyExc_TypeError
,
171 "descriptor '%.200s' for '%.100s' objects "
172 "doesn't apply to '%.100s' object",
174 descr
->d_type
->tp_name
,
175 obj
->ob_type
->tp_name
);
183 member_set(PyMemberDescrObject
*descr
, PyObject
*obj
, PyObject
*value
)
187 if (descr_setcheck((PyDescrObject
*)descr
, obj
, value
, &res
))
189 return PyMember_SetOne((char *)obj
, descr
->d_member
, value
);
193 getset_set(PyGetSetDescrObject
*descr
, PyObject
*obj
, PyObject
*value
)
197 if (descr_setcheck((PyDescrObject
*)descr
, obj
, value
, &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_TypeError
,
203 "attribute '%.300s' of '%.100s' objects is not writable",
204 descr_name((PyDescrObject
*)descr
),
205 descr
->d_type
->tp_name
);
210 methoddescr_call(PyMethodDescrObject
*descr
, PyObject
*args
, PyObject
*kwds
)
213 PyObject
*self
, *func
, *result
;
215 /* Make sure that the first argument is acceptable as 'self' */
216 assert(PyTuple_Check(args
));
217 argc
= PyTuple_GET_SIZE(args
);
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
);
226 self
= PyTuple_GET_ITEM(args
, 0);
227 if (!PyObject_IsInstance(self
, (PyObject
*)(descr
->d_type
))) {
228 PyErr_Format(PyExc_TypeError
,
229 "descriptor '%.200s' "
230 "requires a '%.100s' object "
231 "but received a '%.100s'",
232 descr_name((PyDescrObject
*)descr
),
233 descr
->d_type
->tp_name
,
234 self
->ob_type
->tp_name
);
238 func
= PyCFunction_New(descr
->d_method
, self
);
241 args
= PyTuple_GetSlice(args
, 1, argc
);
246 result
= PyEval_CallObjectWithKeywords(func
, args
, kwds
);
253 classmethoddescr_call(PyMethodDescrObject
*descr
, PyObject
*args
,
256 PyObject
*func
, *result
;
258 func
= PyCFunction_New(descr
->d_method
, (PyObject
*)descr
->d_type
);
262 result
= PyEval_CallObjectWithKeywords(func
, args
, kwds
);
268 wrapperdescr_call(PyWrapperDescrObject
*descr
, PyObject
*args
, PyObject
*kwds
)
271 PyObject
*self
, *func
, *result
;
273 /* Make sure that the first argument is acceptable as 'self' */
274 assert(PyTuple_Check(args
));
275 argc
= PyTuple_GET_SIZE(args
);
277 PyErr_Format(PyExc_TypeError
,
278 "descriptor '%.300s' of '%.100s' "
279 "object needs an argument",
280 descr_name((PyDescrObject
*)descr
),
281 descr
->d_type
->tp_name
);
284 self
= PyTuple_GET_ITEM(args
, 0);
285 if (!PyObject_IsInstance(self
, (PyObject
*)(descr
->d_type
))) {
286 PyErr_Format(PyExc_TypeError
,
287 "descriptor '%.200s' "
288 "requires a '%.100s' object "
289 "but received a '%.100s'",
290 descr_name((PyDescrObject
*)descr
),
291 descr
->d_type
->tp_name
,
292 self
->ob_type
->tp_name
);
296 func
= PyWrapper_New((PyObject
*)descr
, self
);
299 args
= PyTuple_GetSlice(args
, 1, argc
);
304 result
= PyEval_CallObjectWithKeywords(func
, args
, kwds
);
311 method_get_doc(PyMethodDescrObject
*descr
, void *closure
)
313 if (descr
->d_method
->ml_doc
== NULL
) {
317 return PyString_FromString(descr
->d_method
->ml_doc
);
320 static PyMemberDef descr_members
[] = {
321 {"__objclass__", T_OBJECT
, offsetof(PyDescrObject
, d_type
), READONLY
},
322 {"__name__", T_OBJECT
, offsetof(PyDescrObject
, d_name
), READONLY
},
326 static PyGetSetDef method_getset
[] = {
327 {"__doc__", (getter
)method_get_doc
},
332 member_get_doc(PyMemberDescrObject
*descr
, void *closure
)
334 if (descr
->d_member
->doc
== NULL
) {
338 return PyString_FromString(descr
->d_member
->doc
);
341 static PyGetSetDef member_getset
[] = {
342 {"__doc__", (getter
)member_get_doc
},
347 getset_get_doc(PyGetSetDescrObject
*descr
, void *closure
)
349 if (descr
->d_getset
->doc
== NULL
) {
353 return PyString_FromString(descr
->d_getset
->doc
);
356 static PyGetSetDef getset_getset
[] = {
357 {"__doc__", (getter
)getset_get_doc
},
362 wrapper_get_doc(PyWrapperDescrObject
*descr
, void *closure
)
364 if (descr
->d_base
->doc
== NULL
) {
368 return PyString_FromString(descr
->d_base
->doc
);
371 static PyGetSetDef wrapper_getset
[] = {
372 {"__doc__", (getter
)wrapper_get_doc
},
377 descr_traverse(PyObject
*self
, visitproc visit
, void *arg
)
379 PyDescrObject
*descr
= (PyDescrObject
*)self
;
383 err
= visit((PyObject
*)(descr
->d_type
), arg
);
390 static PyTypeObject PyMethodDescr_Type
= {
391 PyObject_HEAD_INIT(&PyType_Type
)
394 sizeof(PyMethodDescrObject
),
396 (destructor
)descr_dealloc
, /* tp_dealloc */
401 (reprfunc
)method_repr
, /* tp_repr */
402 0, /* tp_as_number */
403 0, /* tp_as_sequence */
404 0, /* tp_as_mapping */
406 (ternaryfunc
)methoddescr_call
, /* tp_call */
408 PyObject_GenericGetAttr
, /* tp_getattro */
410 0, /* tp_as_buffer */
411 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
413 descr_traverse
, /* tp_traverse */
415 0, /* tp_richcompare */
416 0, /* tp_weaklistoffset */
420 descr_members
, /* tp_members */
421 method_getset
, /* tp_getset */
424 (descrgetfunc
)method_get
, /* tp_descr_get */
425 0, /* tp_descr_set */
428 /* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */
429 static PyTypeObject PyClassMethodDescr_Type
= {
430 PyObject_HEAD_INIT(&PyType_Type
)
432 "classmethod_descriptor",
433 sizeof(PyMethodDescrObject
),
435 (destructor
)descr_dealloc
, /* tp_dealloc */
440 (reprfunc
)method_repr
, /* tp_repr */
441 0, /* tp_as_number */
442 0, /* tp_as_sequence */
443 0, /* tp_as_mapping */
445 (ternaryfunc
)classmethoddescr_call
, /* tp_call */
447 PyObject_GenericGetAttr
, /* tp_getattro */
449 0, /* tp_as_buffer */
450 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
452 descr_traverse
, /* tp_traverse */
454 0, /* tp_richcompare */
455 0, /* tp_weaklistoffset */
459 descr_members
, /* tp_members */
460 method_getset
, /* tp_getset */
463 (descrgetfunc
)classmethod_get
, /* tp_descr_get */
464 0, /* tp_descr_set */
467 static PyTypeObject PyMemberDescr_Type
= {
468 PyObject_HEAD_INIT(&PyType_Type
)
471 sizeof(PyMemberDescrObject
),
473 (destructor
)descr_dealloc
, /* tp_dealloc */
478 (reprfunc
)member_repr
, /* tp_repr */
479 0, /* tp_as_number */
480 0, /* tp_as_sequence */
481 0, /* tp_as_mapping */
483 (ternaryfunc
)0, /* tp_call */
485 PyObject_GenericGetAttr
, /* tp_getattro */
487 0, /* tp_as_buffer */
488 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
490 descr_traverse
, /* tp_traverse */
492 0, /* tp_richcompare */
493 0, /* tp_weaklistoffset */
497 descr_members
, /* tp_members */
498 member_getset
, /* tp_getset */
501 (descrgetfunc
)member_get
, /* tp_descr_get */
502 (descrsetfunc
)member_set
, /* tp_descr_set */
505 static PyTypeObject PyGetSetDescr_Type
= {
506 PyObject_HEAD_INIT(&PyType_Type
)
509 sizeof(PyGetSetDescrObject
),
511 (destructor
)descr_dealloc
, /* tp_dealloc */
516 (reprfunc
)getset_repr
, /* tp_repr */
517 0, /* tp_as_number */
518 0, /* tp_as_sequence */
519 0, /* tp_as_mapping */
521 (ternaryfunc
)0, /* tp_call */
523 PyObject_GenericGetAttr
, /* tp_getattro */
525 0, /* tp_as_buffer */
526 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
528 descr_traverse
, /* tp_traverse */
530 0, /* tp_richcompare */
531 0, /* tp_weaklistoffset */
535 descr_members
, /* tp_members */
536 getset_getset
, /* tp_getset */
539 (descrgetfunc
)getset_get
, /* tp_descr_get */
540 (descrsetfunc
)getset_set
, /* tp_descr_set */
543 PyTypeObject PyWrapperDescr_Type
= {
544 PyObject_HEAD_INIT(&PyType_Type
)
546 "wrapper_descriptor",
547 sizeof(PyWrapperDescrObject
),
549 (destructor
)descr_dealloc
, /* tp_dealloc */
554 (reprfunc
)wrapper_repr
, /* tp_repr */
555 0, /* tp_as_number */
556 0, /* tp_as_sequence */
557 0, /* tp_as_mapping */
559 (ternaryfunc
)wrapperdescr_call
, /* tp_call */
561 PyObject_GenericGetAttr
, /* tp_getattro */
563 0, /* tp_as_buffer */
564 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
566 descr_traverse
, /* tp_traverse */
568 0, /* tp_richcompare */
569 0, /* tp_weaklistoffset */
573 descr_members
, /* tp_members */
574 wrapper_getset
, /* tp_getset */
577 (descrgetfunc
)wrapper_get
, /* tp_descr_get */
578 0, /* tp_descr_set */
581 static PyDescrObject
*
582 descr_new(PyTypeObject
*descrtype
, PyTypeObject
*type
, char *name
)
584 PyDescrObject
*descr
;
586 descr
= (PyDescrObject
*)PyType_GenericAlloc(descrtype
, 0);
589 descr
->d_type
= type
;
590 descr
->d_name
= PyString_InternFromString(name
);
591 if (descr
->d_name
== NULL
) {
600 PyDescr_NewMethod(PyTypeObject
*type
, PyMethodDef
*method
)
602 PyMethodDescrObject
*descr
;
604 descr
= (PyMethodDescrObject
*)descr_new(&PyMethodDescr_Type
,
605 type
, method
->ml_name
);
607 descr
->d_method
= method
;
608 return (PyObject
*)descr
;
612 PyDescr_NewClassMethod(PyTypeObject
*type
, PyMethodDef
*method
)
614 PyMethodDescrObject
*descr
;
616 descr
= (PyMethodDescrObject
*)descr_new(&PyClassMethodDescr_Type
,
617 type
, method
->ml_name
);
619 descr
->d_method
= method
;
620 return (PyObject
*)descr
;
624 PyDescr_NewMember(PyTypeObject
*type
, PyMemberDef
*member
)
626 PyMemberDescrObject
*descr
;
628 descr
= (PyMemberDescrObject
*)descr_new(&PyMemberDescr_Type
,
631 descr
->d_member
= member
;
632 return (PyObject
*)descr
;
636 PyDescr_NewGetSet(PyTypeObject
*type
, PyGetSetDef
*getset
)
638 PyGetSetDescrObject
*descr
;
640 descr
= (PyGetSetDescrObject
*)descr_new(&PyGetSetDescr_Type
,
643 descr
->d_getset
= getset
;
644 return (PyObject
*)descr
;
648 PyDescr_NewWrapper(PyTypeObject
*type
, struct wrapperbase
*base
, void *wrapped
)
650 PyWrapperDescrObject
*descr
;
652 descr
= (PyWrapperDescrObject
*)descr_new(&PyWrapperDescr_Type
,
655 descr
->d_base
= base
;
656 descr
->d_wrapped
= wrapped
;
658 return (PyObject
*)descr
;
662 /* --- Readonly proxy for dictionaries (actually any mapping) --- */
664 /* This has no reason to be in this file except that adding new files is a
673 proxy_len(proxyobject
*pp
)
675 return PyObject_Size(pp
->dict
);
679 proxy_getitem(proxyobject
*pp
, PyObject
*key
)
681 return PyObject_GetItem(pp
->dict
, key
);
684 static PyMappingMethods proxy_as_mapping
= {
685 (inquiry
)proxy_len
, /* mp_length */
686 (binaryfunc
)proxy_getitem
, /* mp_subscript */
687 0, /* mp_ass_subscript */
691 proxy_contains(proxyobject
*pp
, PyObject
*key
)
693 return PySequence_Contains(pp
->dict
, key
);
696 static PySequenceMethods proxy_as_sequence
= {
703 0, /* sq_ass_slice */
704 (objobjproc
)proxy_contains
, /* sq_contains */
705 0, /* sq_inplace_concat */
706 0, /* sq_inplace_repeat */
710 proxy_has_key(proxyobject
*pp
, PyObject
*key
)
712 int res
= PySequence_Contains(pp
->dict
, key
);
715 return PyBool_FromLong(res
);
719 proxy_get(proxyobject
*pp
, PyObject
*args
)
721 PyObject
*key
, *def
= Py_None
;
723 if (!PyArg_UnpackTuple(args
, "get", 1, 2, &key
, &def
))
725 return PyObject_CallMethod(pp
->dict
, "get", "(OO)", key
, def
);
729 proxy_keys(proxyobject
*pp
)
731 return PyMapping_Keys(pp
->dict
);
735 proxy_values(proxyobject
*pp
)
737 return PyMapping_Values(pp
->dict
);
741 proxy_items(proxyobject
*pp
)
743 return PyMapping_Items(pp
->dict
);
747 proxy_iterkeys(proxyobject
*pp
)
749 return PyObject_CallMethod(pp
->dict
, "iterkeys", NULL
);
753 proxy_itervalues(proxyobject
*pp
)
755 return PyObject_CallMethod(pp
->dict
, "itervalues", NULL
);
759 proxy_iteritems(proxyobject
*pp
)
761 return PyObject_CallMethod(pp
->dict
, "iteritems", NULL
);
764 proxy_copy(proxyobject
*pp
)
766 return PyObject_CallMethod(pp
->dict
, "copy", NULL
);
769 static PyMethodDef proxy_methods
[] = {
770 {"has_key", (PyCFunction
)proxy_has_key
, METH_O
,
771 PyDoc_STR("D.has_key(k) -> True if D has a key k, else False")},
772 {"get", (PyCFunction
)proxy_get
, METH_VARARGS
,
773 PyDoc_STR("D.get(k[,d]) -> D[k] if D.has_key(k), else d."
774 " d defaults to None.")},
775 {"keys", (PyCFunction
)proxy_keys
, METH_NOARGS
,
776 PyDoc_STR("D.keys() -> list of D's keys")},
777 {"values", (PyCFunction
)proxy_values
, METH_NOARGS
,
778 PyDoc_STR("D.values() -> list of D's values")},
779 {"items", (PyCFunction
)proxy_items
, METH_NOARGS
,
780 PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")},
781 {"iterkeys", (PyCFunction
)proxy_iterkeys
, METH_NOARGS
,
782 PyDoc_STR("D.iterkeys() -> an iterator over the keys of D")},
783 {"itervalues",(PyCFunction
)proxy_itervalues
, METH_NOARGS
,
784 PyDoc_STR("D.itervalues() -> an iterator over the values of D")},
785 {"iteritems", (PyCFunction
)proxy_iteritems
, METH_NOARGS
,
786 PyDoc_STR("D.iteritems() ->"
787 " an iterator over the (key, value) items of D")},
788 {"copy", (PyCFunction
)proxy_copy
, METH_NOARGS
,
789 PyDoc_STR("D.copy() -> a shallow copy of D")},
794 proxy_dealloc(proxyobject
*pp
)
796 _PyObject_GC_UNTRACK(pp
);
802 proxy_getiter(proxyobject
*pp
)
804 return PyObject_GetIter(pp
->dict
);
808 proxy_str(proxyobject
*pp
)
810 return PyObject_Str(pp
->dict
);
814 proxy_traverse(PyObject
*self
, visitproc visit
, void *arg
)
816 proxyobject
*pp
= (proxyobject
*)self
;
820 err
= visit(pp
->dict
, arg
);
828 proxy_compare(proxyobject
*v
, PyObject
*w
)
830 return PyObject_Compare(v
->dict
, w
);
834 proxy_richcompare(proxyobject
*v
, PyObject
*w
, int op
)
836 return PyObject_RichCompare(v
->dict
, w
, op
);
839 static PyTypeObject proxytype
= {
840 PyObject_HEAD_INIT(&PyType_Type
)
842 "dictproxy", /* tp_name */
843 sizeof(proxyobject
), /* tp_basicsize */
846 (destructor
)proxy_dealloc
, /* tp_dealloc */
850 (cmpfunc
)proxy_compare
, /* tp_compare */
852 0, /* tp_as_number */
853 &proxy_as_sequence
, /* tp_as_sequence */
854 &proxy_as_mapping
, /* tp_as_mapping */
857 (reprfunc
)proxy_str
, /* tp_str */
858 PyObject_GenericGetAttr
, /* tp_getattro */
860 0, /* tp_as_buffer */
861 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
863 proxy_traverse
, /* tp_traverse */
865 (richcmpfunc
)proxy_richcompare
, /* tp_richcompare */
866 0, /* tp_weaklistoffset */
867 (getiterfunc
)proxy_getiter
, /* tp_iter */
869 proxy_methods
, /* tp_methods */
874 0, /* tp_descr_get */
875 0, /* tp_descr_set */
879 PyDictProxy_New(PyObject
*dict
)
883 pp
= PyObject_GC_New(proxyobject
, &proxytype
);
887 _PyObject_GC_TRACK(pp
);
889 return (PyObject
*)pp
;
893 /* --- Wrapper object for "slot" methods --- */
895 /* This has no reason to be in this file except that adding new files is a
900 PyWrapperDescrObject
*descr
;
905 wrapper_dealloc(wrapperobject
*wp
)
907 _PyObject_GC_UNTRACK(wp
);
908 Py_XDECREF(wp
->descr
);
909 Py_XDECREF(wp
->self
);
913 static PyMethodDef wrapper_methods
[] = {
918 wrapper_name(wrapperobject
*wp
)
920 char *s
= wp
->descr
->d_base
->name
;
922 return PyString_FromString(s
);
926 wrapper_doc(wrapperobject
*wp
)
928 char *s
= wp
->descr
->d_base
->doc
;
935 return PyString_FromString(s
);
939 static PyGetSetDef wrapper_getsets
[] = {
940 {"__name__", (getter
)wrapper_name
},
941 {"__doc__", (getter
)wrapper_doc
},
946 wrapper_call(wrapperobject
*wp
, PyObject
*args
, PyObject
*kwds
)
948 wrapperfunc wrapper
= wp
->descr
->d_base
->wrapper
;
949 PyObject
*self
= wp
->self
;
951 if (wp
->descr
->d_base
->flags
& PyWrapperFlag_KEYWORDS
) {
952 wrapperfunc_kwds wk
= (wrapperfunc_kwds
)wrapper
;
953 return (*wk
)(self
, args
, wp
->descr
->d_wrapped
, kwds
);
956 if (kwds
!= NULL
&& (!PyDict_Check(kwds
) || PyDict_Size(kwds
) != 0)) {
957 PyErr_Format(PyExc_TypeError
,
958 "wrapper %s doesn't take keyword arguments",
959 wp
->descr
->d_base
->name
);
962 return (*wrapper
)(self
, args
, wp
->descr
->d_wrapped
);
966 wrapper_traverse(PyObject
*self
, visitproc visit
, void *arg
)
968 wrapperobject
*wp
= (wrapperobject
*)self
;
972 err
= visit((PyObject
*)(wp
->descr
), arg
);
977 err
= visit(wp
->self
, arg
);
984 static PyTypeObject wrappertype
= {
985 PyObject_HEAD_INIT(&PyType_Type
)
987 "method-wrapper", /* tp_name */
988 sizeof(wrapperobject
), /* tp_basicsize */
991 (destructor
)wrapper_dealloc
, /* tp_dealloc */
997 0, /* tp_as_number */
998 0, /* tp_as_sequence */
999 0, /* tp_as_mapping */
1001 (ternaryfunc
)wrapper_call
, /* tp_call */
1003 PyObject_GenericGetAttr
, /* tp_getattro */
1004 0, /* tp_setattro */
1005 0, /* tp_as_buffer */
1006 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
1008 wrapper_traverse
, /* tp_traverse */
1010 0, /* tp_richcompare */
1011 0, /* tp_weaklistoffset */
1013 0, /* tp_iternext */
1014 wrapper_methods
, /* tp_methods */
1016 wrapper_getsets
, /* tp_getset */
1019 0, /* tp_descr_get */
1020 0, /* tp_descr_set */
1024 PyWrapper_New(PyObject
*d
, PyObject
*self
)
1027 PyWrapperDescrObject
*descr
;
1029 assert(PyObject_TypeCheck(d
, &PyWrapperDescr_Type
));
1030 descr
= (PyWrapperDescrObject
*)d
;
1031 assert(PyObject_IsInstance(self
, (PyObject
*)(descr
->d_type
)));
1033 wp
= PyObject_GC_New(wrapperobject
, &wrappertype
);
1039 _PyObject_GC_TRACK(wp
);
1041 return (PyObject
*)wp
;
1045 /* A built-in 'property' type */
1048 class property(object):
1050 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
1056 def __get__(self, inst, type=None):
1059 if self.__get is None:
1060 raise AttributeError, "unreadable attribute"
1061 return self.__get(inst)
1063 def __set__(self, inst, value):
1064 if self.__set is None:
1065 raise AttributeError, "can't set attribute"
1066 return self.__set(inst, value)
1068 def __delete__(self, inst):
1069 if self.__del is None:
1070 raise AttributeError, "can't delete attribute"
1071 return self.__del(inst)
1083 static PyMemberDef property_members
[] = {
1084 {"fget", T_OBJECT
, offsetof(propertyobject
, prop_get
), READONLY
},
1085 {"fset", T_OBJECT
, offsetof(propertyobject
, prop_set
), READONLY
},
1086 {"fdel", T_OBJECT
, offsetof(propertyobject
, prop_del
), READONLY
},
1087 {"__doc__", T_OBJECT
, offsetof(propertyobject
, prop_doc
), READONLY
},
1093 property_dealloc(PyObject
*self
)
1095 propertyobject
*gs
= (propertyobject
*)self
;
1097 _PyObject_GC_UNTRACK(self
);
1098 Py_XDECREF(gs
->prop_get
);
1099 Py_XDECREF(gs
->prop_set
);
1100 Py_XDECREF(gs
->prop_del
);
1101 Py_XDECREF(gs
->prop_doc
);
1102 self
->ob_type
->tp_free(self
);
1106 property_descr_get(PyObject
*self
, PyObject
*obj
, PyObject
*type
)
1108 propertyobject
*gs
= (propertyobject
*)self
;
1110 if (obj
== NULL
|| obj
== Py_None
) {
1114 if (gs
->prop_get
== NULL
) {
1115 PyErr_SetString(PyExc_AttributeError
, "unreadable attribute");
1118 return PyObject_CallFunction(gs
->prop_get
, "(O)", obj
);
1122 property_descr_set(PyObject
*self
, PyObject
*obj
, PyObject
*value
)
1124 propertyobject
*gs
= (propertyobject
*)self
;
1125 PyObject
*func
, *res
;
1128 func
= gs
->prop_del
;
1130 func
= gs
->prop_set
;
1132 PyErr_SetString(PyExc_AttributeError
,
1134 "can't delete attribute" :
1135 "can't set attribute");
1139 res
= PyObject_CallFunction(func
, "(O)", obj
);
1141 res
= PyObject_CallFunction(func
, "(OO)", obj
, value
);
1149 property_init(PyObject
*self
, PyObject
*args
, PyObject
*kwds
)
1151 PyObject
*get
= NULL
, *set
= NULL
, *del
= NULL
, *doc
= NULL
;
1152 static char *kwlist
[] = {"fget", "fset", "fdel", "doc", 0};
1153 propertyobject
*gs
= (propertyobject
*)self
;
1155 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "|OOOO:property",
1156 kwlist
, &get
, &set
, &del
, &doc
))
1179 PyDoc_STRVAR(property_doc
,
1180 "property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n"
1182 "fget is a function to be used for getting an attribute value, and likewise\n"
1183 "fset is a function for setting, and fdel a function for del'ing, an\n"
1184 "attribute. Typical use is to define a managed attribute x:\n"
1185 "class C(object):\n"
1186 " def getx(self): return self.__x\n"
1187 " def setx(self, value): self.__x = value\n"
1188 " def delx(self): del self.__x\n"
1189 " x = property(getx, setx, delx, \"I'm the 'x' property.\")");
1192 property_traverse(PyObject
*self
, visitproc visit
, void *arg
)
1194 propertyobject
*pp
= (propertyobject
*)self
;
1197 #define VISIT(SLOT) \
1199 err = visit((PyObject *)(pp->SLOT), arg); \
1212 PyTypeObject PyProperty_Type
= {
1213 PyObject_HEAD_INIT(&PyType_Type
)
1215 "property", /* tp_name */
1216 sizeof(propertyobject
), /* tp_basicsize */
1217 0, /* tp_itemsize */
1219 property_dealloc
, /* tp_dealloc */
1225 0, /* tp_as_number */
1226 0, /* tp_as_sequence */
1227 0, /* tp_as_mapping */
1231 PyObject_GenericGetAttr
, /* tp_getattro */
1232 0, /* tp_setattro */
1233 0, /* tp_as_buffer */
1234 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
|
1235 Py_TPFLAGS_BASETYPE
, /* tp_flags */
1236 property_doc
, /* tp_doc */
1237 property_traverse
, /* tp_traverse */
1239 0, /* tp_richcompare */
1240 0, /* tp_weaklistoffset */
1242 0, /* tp_iternext */
1244 property_members
, /* tp_members */
1248 property_descr_get
, /* tp_descr_get */
1249 property_descr_set
, /* tp_descr_set */
1250 0, /* tp_dictoffset */
1251 property_init
, /* tp_init */
1252 PyType_GenericAlloc
, /* tp_alloc */
1253 PyType_GenericNew
, /* tp_new */
1254 PyObject_GC_Del
, /* tp_free */