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 wrapperdescr_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_AttributeError
,
148 "attribute '%.300s' of '%.100s' objects is not readable",
149 descr_name((PyDescrObject
*)descr
),
150 descr
->d_type
->tp_name
);
155 wrapperdescr_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_TypeCheck(obj
, 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_AttributeError
,
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_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
);
239 func
= PyCFunction_New(descr
->d_method
, self
);
242 args
= PyTuple_GetSlice(args
, 1, argc
);
247 result
= PyEval_CallObjectWithKeywords(func
, args
, kwds
);
254 classmethoddescr_call(PyMethodDescrObject
*descr
, PyObject
*args
,
258 PyObject
*self
, *func
, *result
;
260 /* Make sure that the first argument is acceptable as 'self' */
261 assert(PyTuple_Check(args
));
262 argc
= PyTuple_GET_SIZE(args
);
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
);
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
);
280 if (!PyType_IsSubtype((PyTypeObject
*)self
, descr
->d_type
)) {
281 PyErr_Format(PyExc_TypeError
,
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
);
291 func
= PyCFunction_New(descr
->d_method
, self
);
294 args
= PyTuple_GetSlice(args
, 1, argc
);
299 result
= PyEval_CallObjectWithKeywords(func
, args
, kwds
);
306 wrapperdescr_call(PyWrapperDescrObject
*descr
, PyObject
*args
, PyObject
*kwds
)
309 PyObject
*self
, *func
, *result
;
311 /* Make sure that the first argument is acceptable as 'self' */
312 assert(PyTuple_Check(args
));
313 argc
= PyTuple_GET_SIZE(args
);
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
);
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
);
335 func
= PyWrapper_New((PyObject
*)descr
, self
);
338 args
= PyTuple_GetSlice(args
, 1, argc
);
343 result
= PyEval_CallObjectWithKeywords(func
, args
, kwds
);
350 method_get_doc(PyMethodDescrObject
*descr
, void *closure
)
352 if (descr
->d_method
->ml_doc
== NULL
) {
356 return PyString_FromString(descr
->d_method
->ml_doc
);
359 static PyMemberDef descr_members
[] = {
360 {"__objclass__", T_OBJECT
, offsetof(PyDescrObject
, d_type
), READONLY
},
361 {"__name__", T_OBJECT
, offsetof(PyDescrObject
, d_name
), READONLY
},
365 static PyGetSetDef method_getset
[] = {
366 {"__doc__", (getter
)method_get_doc
},
371 member_get_doc(PyMemberDescrObject
*descr
, void *closure
)
373 if (descr
->d_member
->doc
== NULL
) {
377 return PyString_FromString(descr
->d_member
->doc
);
380 static PyGetSetDef member_getset
[] = {
381 {"__doc__", (getter
)member_get_doc
},
386 getset_get_doc(PyGetSetDescrObject
*descr
, void *closure
)
388 if (descr
->d_getset
->doc
== NULL
) {
392 return PyString_FromString(descr
->d_getset
->doc
);
395 static PyGetSetDef getset_getset
[] = {
396 {"__doc__", (getter
)getset_get_doc
},
401 wrapperdescr_get_doc(PyWrapperDescrObject
*descr
, void *closure
)
403 if (descr
->d_base
->doc
== NULL
) {
407 return PyString_FromString(descr
->d_base
->doc
);
410 static PyGetSetDef wrapperdescr_getset
[] = {
411 {"__doc__", (getter
)wrapperdescr_get_doc
},
416 descr_traverse(PyObject
*self
, visitproc visit
, void *arg
)
418 PyDescrObject
*descr
= (PyDescrObject
*)self
;
419 Py_VISIT(descr
->d_type
);
423 static PyTypeObject PyMethodDescr_Type
= {
424 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
426 sizeof(PyMethodDescrObject
),
428 (destructor
)descr_dealloc
, /* tp_dealloc */
433 (reprfunc
)method_repr
, /* tp_repr */
434 0, /* tp_as_number */
435 0, /* tp_as_sequence */
436 0, /* tp_as_mapping */
438 (ternaryfunc
)methoddescr_call
, /* tp_call */
440 PyObject_GenericGetAttr
, /* tp_getattro */
442 0, /* tp_as_buffer */
443 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
445 descr_traverse
, /* tp_traverse */
447 0, /* tp_richcompare */
448 0, /* tp_weaklistoffset */
452 descr_members
, /* tp_members */
453 method_getset
, /* tp_getset */
456 (descrgetfunc
)method_get
, /* tp_descr_get */
457 0, /* tp_descr_set */
460 /* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */
461 static PyTypeObject PyClassMethodDescr_Type
= {
462 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
463 "classmethod_descriptor",
464 sizeof(PyMethodDescrObject
),
466 (destructor
)descr_dealloc
, /* tp_dealloc */
471 (reprfunc
)method_repr
, /* tp_repr */
472 0, /* tp_as_number */
473 0, /* tp_as_sequence */
474 0, /* tp_as_mapping */
476 (ternaryfunc
)classmethoddescr_call
, /* tp_call */
478 PyObject_GenericGetAttr
, /* tp_getattro */
480 0, /* tp_as_buffer */
481 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
483 descr_traverse
, /* tp_traverse */
485 0, /* tp_richcompare */
486 0, /* tp_weaklistoffset */
490 descr_members
, /* tp_members */
491 method_getset
, /* tp_getset */
494 (descrgetfunc
)classmethod_get
, /* tp_descr_get */
495 0, /* tp_descr_set */
498 PyTypeObject PyMemberDescr_Type
= {
499 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
501 sizeof(PyMemberDescrObject
),
503 (destructor
)descr_dealloc
, /* tp_dealloc */
508 (reprfunc
)member_repr
, /* tp_repr */
509 0, /* tp_as_number */
510 0, /* tp_as_sequence */
511 0, /* tp_as_mapping */
515 PyObject_GenericGetAttr
, /* tp_getattro */
517 0, /* tp_as_buffer */
518 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
520 descr_traverse
, /* tp_traverse */
522 0, /* tp_richcompare */
523 0, /* tp_weaklistoffset */
527 descr_members
, /* tp_members */
528 member_getset
, /* tp_getset */
531 (descrgetfunc
)member_get
, /* tp_descr_get */
532 (descrsetfunc
)member_set
, /* tp_descr_set */
535 PyTypeObject PyGetSetDescr_Type
= {
536 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
538 sizeof(PyGetSetDescrObject
),
540 (destructor
)descr_dealloc
, /* tp_dealloc */
545 (reprfunc
)getset_repr
, /* tp_repr */
546 0, /* tp_as_number */
547 0, /* tp_as_sequence */
548 0, /* tp_as_mapping */
552 PyObject_GenericGetAttr
, /* tp_getattro */
554 0, /* tp_as_buffer */
555 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
557 descr_traverse
, /* tp_traverse */
559 0, /* tp_richcompare */
560 0, /* tp_weaklistoffset */
564 descr_members
, /* tp_members */
565 getset_getset
, /* tp_getset */
568 (descrgetfunc
)getset_get
, /* tp_descr_get */
569 (descrsetfunc
)getset_set
, /* tp_descr_set */
572 PyTypeObject PyWrapperDescr_Type
= {
573 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
574 "wrapper_descriptor",
575 sizeof(PyWrapperDescrObject
),
577 (destructor
)descr_dealloc
, /* tp_dealloc */
582 (reprfunc
)wrapperdescr_repr
, /* tp_repr */
583 0, /* tp_as_number */
584 0, /* tp_as_sequence */
585 0, /* tp_as_mapping */
587 (ternaryfunc
)wrapperdescr_call
, /* tp_call */
589 PyObject_GenericGetAttr
, /* tp_getattro */
591 0, /* tp_as_buffer */
592 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
594 descr_traverse
, /* tp_traverse */
596 0, /* tp_richcompare */
597 0, /* tp_weaklistoffset */
601 descr_members
, /* tp_members */
602 wrapperdescr_getset
, /* tp_getset */
605 (descrgetfunc
)wrapperdescr_get
, /* tp_descr_get */
606 0, /* tp_descr_set */
609 static PyDescrObject
*
610 descr_new(PyTypeObject
*descrtype
, PyTypeObject
*type
, const char *name
)
612 PyDescrObject
*descr
;
614 descr
= (PyDescrObject
*)PyType_GenericAlloc(descrtype
, 0);
617 descr
->d_type
= type
;
618 descr
->d_name
= PyString_InternFromString(name
);
619 if (descr
->d_name
== NULL
) {
628 PyDescr_NewMethod(PyTypeObject
*type
, PyMethodDef
*method
)
630 PyMethodDescrObject
*descr
;
632 descr
= (PyMethodDescrObject
*)descr_new(&PyMethodDescr_Type
,
633 type
, method
->ml_name
);
635 descr
->d_method
= method
;
636 return (PyObject
*)descr
;
640 PyDescr_NewClassMethod(PyTypeObject
*type
, PyMethodDef
*method
)
642 PyMethodDescrObject
*descr
;
644 descr
= (PyMethodDescrObject
*)descr_new(&PyClassMethodDescr_Type
,
645 type
, method
->ml_name
);
647 descr
->d_method
= method
;
648 return (PyObject
*)descr
;
652 PyDescr_NewMember(PyTypeObject
*type
, PyMemberDef
*member
)
654 PyMemberDescrObject
*descr
;
656 descr
= (PyMemberDescrObject
*)descr_new(&PyMemberDescr_Type
,
659 descr
->d_member
= member
;
660 return (PyObject
*)descr
;
664 PyDescr_NewGetSet(PyTypeObject
*type
, PyGetSetDef
*getset
)
666 PyGetSetDescrObject
*descr
;
668 descr
= (PyGetSetDescrObject
*)descr_new(&PyGetSetDescr_Type
,
671 descr
->d_getset
= getset
;
672 return (PyObject
*)descr
;
676 PyDescr_NewWrapper(PyTypeObject
*type
, struct wrapperbase
*base
, void *wrapped
)
678 PyWrapperDescrObject
*descr
;
680 descr
= (PyWrapperDescrObject
*)descr_new(&PyWrapperDescr_Type
,
683 descr
->d_base
= base
;
684 descr
->d_wrapped
= wrapped
;
686 return (PyObject
*)descr
;
690 /* --- Readonly proxy for dictionaries (actually any mapping) --- */
692 /* This has no reason to be in this file except that adding new files is a
701 proxy_len(proxyobject
*pp
)
703 return PyObject_Size(pp
->dict
);
707 proxy_getitem(proxyobject
*pp
, PyObject
*key
)
709 return PyObject_GetItem(pp
->dict
, key
);
712 static PyMappingMethods proxy_as_mapping
= {
713 (lenfunc
)proxy_len
, /* mp_length */
714 (binaryfunc
)proxy_getitem
, /* mp_subscript */
715 0, /* mp_ass_subscript */
719 proxy_contains(proxyobject
*pp
, PyObject
*key
)
721 return PyDict_Contains(pp
->dict
, key
);
724 static PySequenceMethods proxy_as_sequence
= {
731 0, /* sq_ass_slice */
732 (objobjproc
)proxy_contains
, /* sq_contains */
733 0, /* sq_inplace_concat */
734 0, /* sq_inplace_repeat */
738 proxy_has_key(proxyobject
*pp
, PyObject
*key
)
740 int res
= PyDict_Contains(pp
->dict
, key
);
743 return PyBool_FromLong(res
);
747 proxy_get(proxyobject
*pp
, PyObject
*args
)
749 PyObject
*key
, *def
= Py_None
;
751 if (!PyArg_UnpackTuple(args
, "get", 1, 2, &key
, &def
))
753 return PyObject_CallMethod(pp
->dict
, "get", "(OO)", key
, def
);
757 proxy_keys(proxyobject
*pp
)
759 return PyMapping_Keys(pp
->dict
);
763 proxy_values(proxyobject
*pp
)
765 return PyMapping_Values(pp
->dict
);
769 proxy_items(proxyobject
*pp
)
771 return PyMapping_Items(pp
->dict
);
775 proxy_iterkeys(proxyobject
*pp
)
777 return PyObject_CallMethod(pp
->dict
, "iterkeys", NULL
);
781 proxy_itervalues(proxyobject
*pp
)
783 return PyObject_CallMethod(pp
->dict
, "itervalues", NULL
);
787 proxy_iteritems(proxyobject
*pp
)
789 return PyObject_CallMethod(pp
->dict
, "iteritems", NULL
);
792 proxy_copy(proxyobject
*pp
)
794 return PyObject_CallMethod(pp
->dict
, "copy", NULL
);
797 static 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")},
822 proxy_dealloc(proxyobject
*pp
)
824 _PyObject_GC_UNTRACK(pp
);
830 proxy_getiter(proxyobject
*pp
)
832 return PyObject_GetIter(pp
->dict
);
836 proxy_str(proxyobject
*pp
)
838 return PyObject_Str(pp
->dict
);
842 proxy_repr(proxyobject
*pp
)
847 dictrepr
= PyObject_Repr(pp
->dict
);
848 if (dictrepr
== NULL
)
850 result
= PyString_FromFormat("dict_proxy(%s)", PyString_AS_STRING(dictrepr
));
856 proxy_traverse(PyObject
*self
, visitproc visit
, void *arg
)
858 proxyobject
*pp
= (proxyobject
*)self
;
864 proxy_compare(proxyobject
*v
, PyObject
*w
)
866 return PyObject_Compare(v
->dict
, w
);
870 proxy_richcompare(proxyobject
*v
, PyObject
*w
, int op
)
872 return PyObject_RichCompare(v
->dict
, w
, op
);
875 PyTypeObject PyDictProxy_Type
= {
876 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
877 "dictproxy", /* tp_name */
878 sizeof(proxyobject
), /* tp_basicsize */
881 (destructor
)proxy_dealloc
, /* tp_dealloc */
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 */
892 (reprfunc
)proxy_str
, /* tp_str */
893 PyObject_GenericGetAttr
, /* tp_getattro */
895 0, /* tp_as_buffer */
896 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
898 proxy_traverse
, /* tp_traverse */
900 (richcmpfunc
)proxy_richcompare
, /* tp_richcompare */
901 0, /* tp_weaklistoffset */
902 (getiterfunc
)proxy_getiter
, /* tp_iter */
904 proxy_methods
, /* tp_methods */
909 0, /* tp_descr_get */
910 0, /* tp_descr_set */
914 PyDictProxy_New(PyObject
*dict
)
918 pp
= PyObject_GC_New(proxyobject
, &PyDictProxy_Type
);
922 _PyObject_GC_TRACK(pp
);
924 return (PyObject
*)pp
;
928 /* --- Wrapper object for "slot" methods --- */
930 /* This has no reason to be in this file except that adding new files is a
935 PyWrapperDescrObject
*descr
;
940 wrapper_dealloc(wrapperobject
*wp
)
942 PyObject_GC_UnTrack(wp
);
943 Py_TRASHCAN_SAFE_BEGIN(wp
)
944 Py_XDECREF(wp
->descr
);
945 Py_XDECREF(wp
->self
);
947 Py_TRASHCAN_SAFE_END(wp
)
951 wrapper_compare(wrapperobject
*a
, wrapperobject
*b
)
953 if (a
->descr
== b
->descr
)
954 return PyObject_Compare(a
->self
, b
->self
);
956 return (a
->descr
< b
->descr
) ? -1 : 1;
960 wrapper_hash(wrapperobject
*wp
)
963 x
= _Py_HashPointer(wp
->descr
);
966 y
= PyObject_Hash(wp
->self
);
976 wrapper_repr(wrapperobject
*wp
)
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
,
984 static PyMemberDef wrapper_members
[] = {
985 {"__self__", T_OBJECT
, offsetof(wrapperobject
, self
), READONLY
},
990 wrapper_objclass(wrapperobject
*wp
)
992 PyObject
*c
= (PyObject
*)wp
->descr
->d_type
;
999 wrapper_name(wrapperobject
*wp
)
1001 char *s
= wp
->descr
->d_base
->name
;
1003 return PyString_FromString(s
);
1007 wrapper_doc(wrapperobject
*wp
)
1009 char *s
= wp
->descr
->d_base
->doc
;
1016 return PyString_FromString(s
);
1020 static PyGetSetDef wrapper_getsets
[] = {
1021 {"__objclass__", (getter
)wrapper_objclass
},
1022 {"__name__", (getter
)wrapper_name
},
1023 {"__doc__", (getter
)wrapper_doc
},
1028 wrapper_call(wrapperobject
*wp
, PyObject
*args
, PyObject
*kwds
)
1030 wrapperfunc wrapper
= wp
->descr
->d_base
->wrapper
;
1031 PyObject
*self
= wp
->self
;
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
);
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
);
1044 return (*wrapper
)(self
, args
, wp
->descr
->d_wrapped
);
1048 wrapper_traverse(PyObject
*self
, visitproc visit
, void *arg
)
1050 wrapperobject
*wp
= (wrapperobject
*)self
;
1051 Py_VISIT(wp
->descr
);
1056 static PyTypeObject wrappertype
= {
1057 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
1058 "method-wrapper", /* tp_name */
1059 sizeof(wrapperobject
), /* tp_basicsize */
1060 0, /* tp_itemsize */
1062 (destructor
)wrapper_dealloc
, /* tp_dealloc */
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 */
1074 PyObject_GenericGetAttr
, /* tp_getattro */
1075 0, /* tp_setattro */
1076 0, /* tp_as_buffer */
1077 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
1079 wrapper_traverse
, /* tp_traverse */
1081 0, /* tp_richcompare */
1082 0, /* tp_weaklistoffset */
1084 0, /* tp_iternext */
1086 wrapper_members
, /* tp_members */
1087 wrapper_getsets
, /* tp_getset */
1090 0, /* tp_descr_get */
1091 0, /* tp_descr_set */
1095 PyWrapper_New(PyObject
*d
, PyObject
*self
)
1098 PyWrapperDescrObject
*descr
;
1100 assert(PyObject_TypeCheck(d
, &PyWrapperDescr_Type
));
1101 descr
= (PyWrapperDescrObject
*)d
;
1102 assert(_PyObject_RealIsSubclass((PyObject
*)Py_TYPE(self
),
1103 (PyObject
*)(descr
->d_type
)));
1105 wp
= PyObject_GC_New(wrapperobject
, &wrappertype
);
1111 _PyObject_GC_TRACK(wp
);
1113 return (PyObject
*)wp
;
1117 /* A built-in 'property' type */
1120 class property(object):
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__"):
1130 def __get__(self, inst, type=None):
1133 if self.__get is None:
1134 raise AttributeError, "unreadable attribute"
1135 return self.__get(inst)
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)
1142 def __delete__(self, inst):
1143 if self.__del is None:
1144 raise AttributeError, "can't delete attribute"
1145 return self.__del(inst)
1158 static PyObject
* property_copy(PyObject
*, PyObject
*, PyObject
*,
1161 static 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
},
1170 PyDoc_STRVAR(getter_doc
,
1171 "Descriptor to change the getter on a property.");
1174 property_getter(PyObject
*self
, PyObject
*getter
)
1176 return property_copy(self
, getter
, NULL
, NULL
);
1180 PyDoc_STRVAR(setter_doc
,
1181 "Descriptor to change the setter on a property.");
1184 property_setter(PyObject
*self
, PyObject
*setter
)
1186 return property_copy(self
, NULL
, setter
, NULL
);
1190 PyDoc_STRVAR(deleter_doc
,
1191 "Descriptor to change the deleter on a property.");
1194 property_deleter(PyObject
*self
, PyObject
*deleter
)
1196 return property_copy(self
, NULL
, NULL
, deleter
);
1200 static 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
},
1209 property_dealloc(PyObject
*self
)
1211 propertyobject
*gs
= (propertyobject
*)self
;
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
);
1222 property_descr_get(PyObject
*self
, PyObject
*obj
, PyObject
*type
)
1224 propertyobject
*gs
= (propertyobject
*)self
;
1226 if (obj
== NULL
|| obj
== Py_None
) {
1230 if (gs
->prop_get
== NULL
) {
1231 PyErr_SetString(PyExc_AttributeError
, "unreadable attribute");
1234 return PyObject_CallFunction(gs
->prop_get
, "(O)", obj
);
1238 property_descr_set(PyObject
*self
, PyObject
*obj
, PyObject
*value
)
1240 propertyobject
*gs
= (propertyobject
*)self
;
1241 PyObject
*func
, *res
;
1244 func
= gs
->prop_del
;
1246 func
= gs
->prop_set
;
1248 PyErr_SetString(PyExc_AttributeError
,
1250 "can't delete attribute" :
1251 "can't set attribute");
1255 res
= PyObject_CallFunction(func
, "(O)", obj
);
1257 res
= PyObject_CallFunction(func
, "(OO)", obj
, value
);
1265 property_copy(PyObject
*old
, PyObject
*get
, PyObject
*set
, PyObject
*del
)
1267 propertyobject
*pold
= (propertyobject
*)old
;
1268 PyObject
*new, *type
, *doc
;
1270 type
= PyObject_Type(old
);
1274 if (get
== NULL
|| get
== Py_None
) {
1276 get
= pold
->prop_get
? pold
->prop_get
: Py_None
;
1278 if (set
== NULL
|| set
== Py_None
) {
1280 set
= pold
->prop_set
? pold
->prop_set
: Py_None
;
1282 if (del
== NULL
|| del
== Py_None
) {
1284 del
= pold
->prop_del
? pold
->prop_del
: Py_None
;
1286 if (pold
->getter_doc
&& get
!= Py_None
) {
1287 /* make _init use __doc__ from getter */
1291 doc
= pold
->prop_doc
? pold
->prop_doc
: Py_None
;
1294 new = PyObject_CallFunction(type
, "OOOO", get
, set
, del
, doc
);
1302 property_init(PyObject
*self
, PyObject
*args
, PyObject
*kwds
)
1304 PyObject
*get
= NULL
, *set
= NULL
, *del
= NULL
, *doc
= NULL
;
1305 static char *kwlist
[] = {"fget", "fset", "fdel", "doc", 0};
1306 propertyobject
*prop
= (propertyobject
*)self
;
1308 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "|OOOO:property",
1309 kwlist
, &get
, &set
, &del
, &doc
))
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;
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__");
1334 if (Py_TYPE(self
) == &PyProperty_Type
) {
1335 Py_XDECREF(prop
->prop_doc
);
1336 prop
->prop_doc
= get_doc
;
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
1343 int err
= PyObject_SetAttrString(self
, "__doc__", get_doc
);
1348 prop
->getter_doc
= 1;
1350 else if (PyErr_ExceptionMatches(PyExc_Exception
)) {
1361 PyDoc_STRVAR(property_doc
,
1362 "property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\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"
1373 "Decorators make defining new properties or modifying existing ones easy:\n\n"
1374 "class C(object):\n"
1377 " \"I am the 'x' property.\"\n"
1380 " def x(self, value):\n"
1381 " self._x = value\n"
1388 property_traverse(PyObject
*self
, visitproc visit
, void *arg
)
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
);
1398 PyTypeObject PyProperty_Type
= {
1399 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
1400 "property", /* tp_name */
1401 sizeof(propertyobject
), /* tp_basicsize */
1402 0, /* tp_itemsize */
1404 property_dealloc
, /* tp_dealloc */
1410 0, /* tp_as_number */
1411 0, /* tp_as_sequence */
1412 0, /* tp_as_mapping */
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 */
1424 0, /* tp_richcompare */
1425 0, /* tp_weaklistoffset */
1427 0, /* tp_iternext */
1428 property_methods
, /* tp_methods */
1429 property_members
, /* tp_members */
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 */