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
&& PyUnicode_Check(descr
->d_name
))
24 descr_repr(PyDescrObject
*descr
, char *format
)
26 PyObject
*name
= NULL
;
27 if (descr
->d_name
!= NULL
&& PyUnicode_Check(descr
->d_name
))
30 return PyUnicode_FromFormat(format
, name
, "?", descr
->d_type
->tp_name
);
34 method_repr(PyMethodDescrObject
*descr
)
36 return descr_repr((PyDescrObject
*)descr
,
37 "<method '%V' of '%s' objects>");
41 member_repr(PyMemberDescrObject
*descr
)
43 return descr_repr((PyDescrObject
*)descr
,
44 "<member '%V' of '%s' objects>");
48 getset_repr(PyGetSetDescrObject
*descr
)
50 return descr_repr((PyDescrObject
*)descr
,
51 "<attribute '%V' of '%s' objects>");
55 wrapperdescr_repr(PyWrapperDescrObject
*descr
)
57 return descr_repr((PyDescrObject
*)descr
,
58 "<slot wrapper '%V' of '%s' objects>");
62 descr_check(PyDescrObject
*descr
, PyObject
*obj
, PyObject
**pres
)
66 *pres
= (PyObject
*)descr
;
69 if (!PyObject_TypeCheck(obj
, descr
->d_type
)) {
70 PyErr_Format(PyExc_TypeError
,
71 "descriptor '%V' for '%s' objects "
72 "doesn't apply to '%s' object",
73 descr_name((PyDescrObject
*)descr
), "?",
74 descr
->d_type
->tp_name
,
75 obj
->ob_type
->tp_name
);
83 classmethod_get(PyMethodDescrObject
*descr
, PyObject
*obj
, PyObject
*type
)
85 /* Ensure a valid type. Class methods ignore obj. */
88 type
= (PyObject
*)obj
->ob_type
;
91 PyErr_Format(PyExc_TypeError
,
92 "descriptor '%V' for type '%s' "
93 "needs either an object or a type",
94 descr_name((PyDescrObject
*)descr
), "?",
95 descr
->d_type
->tp_name
);
99 if (!PyType_Check(type
)) {
100 PyErr_Format(PyExc_TypeError
,
101 "descriptor '%V' for type '%s' "
102 "needs a type, not a '%s' as arg 2",
103 descr_name((PyDescrObject
*)descr
), "?",
104 descr
->d_type
->tp_name
,
105 type
->ob_type
->tp_name
);
108 if (!PyType_IsSubtype((PyTypeObject
*)type
, descr
->d_type
)) {
109 PyErr_Format(PyExc_TypeError
,
110 "descriptor '%V' for type '%s' "
111 "doesn't apply to type '%s'",
112 descr_name((PyDescrObject
*)descr
), "?",
113 descr
->d_type
->tp_name
,
114 ((PyTypeObject
*)type
)->tp_name
);
117 return PyCFunction_New(descr
->d_method
, type
);
121 method_get(PyMethodDescrObject
*descr
, PyObject
*obj
, PyObject
*type
)
125 if (descr_check((PyDescrObject
*)descr
, obj
, &res
))
127 return PyCFunction_New(descr
->d_method
, obj
);
131 member_get(PyMemberDescrObject
*descr
, PyObject
*obj
, PyObject
*type
)
135 if (descr_check((PyDescrObject
*)descr
, obj
, &res
))
137 return PyMember_GetOne((char *)obj
, descr
->d_member
);
141 getset_get(PyGetSetDescrObject
*descr
, PyObject
*obj
, PyObject
*type
)
145 if (descr_check((PyDescrObject
*)descr
, obj
, &res
))
147 if (descr
->d_getset
->get
!= NULL
)
148 return descr
->d_getset
->get(obj
, descr
->d_getset
->closure
);
149 PyErr_Format(PyExc_AttributeError
,
150 "attribute '%V' of '%.100s' objects is not readable",
151 descr_name((PyDescrObject
*)descr
), "?",
152 descr
->d_type
->tp_name
);
157 wrapperdescr_get(PyWrapperDescrObject
*descr
, PyObject
*obj
, PyObject
*type
)
161 if (descr_check((PyDescrObject
*)descr
, obj
, &res
))
163 return PyWrapper_New((PyObject
*)descr
, obj
);
167 descr_setcheck(PyDescrObject
*descr
, PyObject
*obj
, PyObject
*value
,
171 if (!PyObject_TypeCheck(obj
, descr
->d_type
)) {
172 PyErr_Format(PyExc_TypeError
,
173 "descriptor '%V' for '%.100s' objects "
174 "doesn't apply to '%.100s' object",
175 descr_name(descr
), "?",
176 descr
->d_type
->tp_name
,
177 obj
->ob_type
->tp_name
);
185 member_set(PyMemberDescrObject
*descr
, PyObject
*obj
, PyObject
*value
)
189 if (descr_setcheck((PyDescrObject
*)descr
, obj
, value
, &res
))
191 return PyMember_SetOne((char *)obj
, descr
->d_member
, value
);
195 getset_set(PyGetSetDescrObject
*descr
, PyObject
*obj
, PyObject
*value
)
199 if (descr_setcheck((PyDescrObject
*)descr
, obj
, value
, &res
))
201 if (descr
->d_getset
->set
!= NULL
)
202 return descr
->d_getset
->set(obj
, value
,
203 descr
->d_getset
->closure
);
204 PyErr_Format(PyExc_AttributeError
,
205 "attribute '%V' of '%.100s' objects is not writable",
206 descr_name((PyDescrObject
*)descr
), "?",
207 descr
->d_type
->tp_name
);
212 methoddescr_call(PyMethodDescrObject
*descr
, PyObject
*args
, PyObject
*kwds
)
215 PyObject
*self
, *func
, *result
;
217 /* Make sure that the first argument is acceptable as 'self' */
218 assert(PyTuple_Check(args
));
219 argc
= PyTuple_GET_SIZE(args
);
221 PyErr_Format(PyExc_TypeError
,
222 "descriptor '%V' of '%.100s' "
223 "object needs an argument",
224 descr_name((PyDescrObject
*)descr
), "?",
225 descr
->d_type
->tp_name
);
228 self
= PyTuple_GET_ITEM(args
, 0);
229 if (!PyObject_IsInstance(self
, (PyObject
*)(descr
->d_type
))) {
230 PyErr_Format(PyExc_TypeError
,
232 "requires a '%.100s' object "
233 "but received a '%.100s'",
234 descr_name((PyDescrObject
*)descr
), "?",
235 descr
->d_type
->tp_name
,
236 self
->ob_type
->tp_name
);
240 func
= PyCFunction_New(descr
->d_method
, self
);
243 args
= PyTuple_GetSlice(args
, 1, argc
);
248 result
= PyEval_CallObjectWithKeywords(func
, args
, kwds
);
255 classmethoddescr_call(PyMethodDescrObject
*descr
, PyObject
*args
,
258 PyObject
*func
, *result
;
260 func
= PyCFunction_New(descr
->d_method
, (PyObject
*)descr
->d_type
);
264 result
= PyEval_CallObjectWithKeywords(func
, args
, kwds
);
270 wrapperdescr_call(PyWrapperDescrObject
*descr
, PyObject
*args
, PyObject
*kwds
)
273 PyObject
*self
, *func
, *result
;
275 /* Make sure that the first argument is acceptable as 'self' */
276 assert(PyTuple_Check(args
));
277 argc
= PyTuple_GET_SIZE(args
);
279 PyErr_Format(PyExc_TypeError
,
280 "descriptor '%V' of '%.100s' "
281 "object needs an argument",
282 descr_name((PyDescrObject
*)descr
), "?",
283 descr
->d_type
->tp_name
);
286 self
= PyTuple_GET_ITEM(args
, 0);
287 if (!PyObject_IsInstance(self
, (PyObject
*)(descr
->d_type
))) {
288 PyErr_Format(PyExc_TypeError
,
290 "requires a '%.100s' object "
291 "but received a '%.100s'",
292 descr_name((PyDescrObject
*)descr
), "?",
293 descr
->d_type
->tp_name
,
294 self
->ob_type
->tp_name
);
298 func
= PyWrapper_New((PyObject
*)descr
, self
);
301 args
= PyTuple_GetSlice(args
, 1, argc
);
306 result
= PyEval_CallObjectWithKeywords(func
, args
, kwds
);
313 method_get_doc(PyMethodDescrObject
*descr
, void *closure
)
315 if (descr
->d_method
->ml_doc
== NULL
) {
319 return PyUnicode_FromString(descr
->d_method
->ml_doc
);
322 static PyMemberDef descr_members
[] = {
323 {"__objclass__", T_OBJECT
, offsetof(PyDescrObject
, d_type
), READONLY
},
324 {"__name__", T_OBJECT
, offsetof(PyDescrObject
, d_name
), READONLY
},
328 static PyGetSetDef method_getset
[] = {
329 {"__doc__", (getter
)method_get_doc
},
334 member_get_doc(PyMemberDescrObject
*descr
, void *closure
)
336 if (descr
->d_member
->doc
== NULL
) {
340 return PyUnicode_FromString(descr
->d_member
->doc
);
343 static PyGetSetDef member_getset
[] = {
344 {"__doc__", (getter
)member_get_doc
},
349 getset_get_doc(PyGetSetDescrObject
*descr
, void *closure
)
351 if (descr
->d_getset
->doc
== NULL
) {
355 return PyUnicode_FromString(descr
->d_getset
->doc
);
358 static PyGetSetDef getset_getset
[] = {
359 {"__doc__", (getter
)getset_get_doc
},
364 wrapperdescr_get_doc(PyWrapperDescrObject
*descr
, void *closure
)
366 if (descr
->d_base
->doc
== NULL
) {
370 return PyUnicode_FromString(descr
->d_base
->doc
);
373 static PyGetSetDef wrapperdescr_getset
[] = {
374 {"__doc__", (getter
)wrapperdescr_get_doc
},
379 descr_traverse(PyObject
*self
, visitproc visit
, void *arg
)
381 PyDescrObject
*descr
= (PyDescrObject
*)self
;
382 Py_VISIT(descr
->d_type
);
386 PyTypeObject PyMethodDescr_Type
= {
387 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
389 sizeof(PyMethodDescrObject
),
391 (destructor
)descr_dealloc
, /* tp_dealloc */
396 (reprfunc
)method_repr
, /* tp_repr */
397 0, /* tp_as_number */
398 0, /* tp_as_sequence */
399 0, /* tp_as_mapping */
401 (ternaryfunc
)methoddescr_call
, /* tp_call */
403 PyObject_GenericGetAttr
, /* tp_getattro */
405 0, /* tp_as_buffer */
406 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
408 descr_traverse
, /* tp_traverse */
410 0, /* tp_richcompare */
411 0, /* tp_weaklistoffset */
415 descr_members
, /* tp_members */
416 method_getset
, /* tp_getset */
419 (descrgetfunc
)method_get
, /* tp_descr_get */
420 0, /* tp_descr_set */
423 /* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */
424 PyTypeObject PyClassMethodDescr_Type
= {
425 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
426 "classmethod_descriptor",
427 sizeof(PyMethodDescrObject
),
429 (destructor
)descr_dealloc
, /* tp_dealloc */
434 (reprfunc
)method_repr
, /* tp_repr */
435 0, /* tp_as_number */
436 0, /* tp_as_sequence */
437 0, /* tp_as_mapping */
439 (ternaryfunc
)classmethoddescr_call
, /* tp_call */
441 PyObject_GenericGetAttr
, /* tp_getattro */
443 0, /* tp_as_buffer */
444 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
446 descr_traverse
, /* tp_traverse */
448 0, /* tp_richcompare */
449 0, /* tp_weaklistoffset */
453 descr_members
, /* tp_members */
454 method_getset
, /* tp_getset */
457 (descrgetfunc
)classmethod_get
, /* tp_descr_get */
458 0, /* tp_descr_set */
461 PyTypeObject PyMemberDescr_Type
= {
462 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
464 sizeof(PyMemberDescrObject
),
466 (destructor
)descr_dealloc
, /* tp_dealloc */
471 (reprfunc
)member_repr
, /* tp_repr */
472 0, /* tp_as_number */
473 0, /* tp_as_sequence */
474 0, /* tp_as_mapping */
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 member_getset
, /* tp_getset */
494 (descrgetfunc
)member_get
, /* tp_descr_get */
495 (descrsetfunc
)member_set
, /* tp_descr_set */
498 PyTypeObject PyGetSetDescr_Type
= {
499 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
501 sizeof(PyGetSetDescrObject
),
503 (destructor
)descr_dealloc
, /* tp_dealloc */
508 (reprfunc
)getset_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 getset_getset
, /* tp_getset */
531 (descrgetfunc
)getset_get
, /* tp_descr_get */
532 (descrsetfunc
)getset_set
, /* tp_descr_set */
535 PyTypeObject PyWrapperDescr_Type
= {
536 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
537 "wrapper_descriptor",
538 sizeof(PyWrapperDescrObject
),
540 (destructor
)descr_dealloc
, /* tp_dealloc */
545 (reprfunc
)wrapperdescr_repr
, /* tp_repr */
546 0, /* tp_as_number */
547 0, /* tp_as_sequence */
548 0, /* tp_as_mapping */
550 (ternaryfunc
)wrapperdescr_call
, /* tp_call */
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 wrapperdescr_getset
, /* tp_getset */
568 (descrgetfunc
)wrapperdescr_get
, /* tp_descr_get */
569 0, /* tp_descr_set */
572 static PyDescrObject
*
573 descr_new(PyTypeObject
*descrtype
, PyTypeObject
*type
, const char *name
)
575 PyDescrObject
*descr
;
577 descr
= (PyDescrObject
*)PyType_GenericAlloc(descrtype
, 0);
580 descr
->d_type
= type
;
581 descr
->d_name
= PyUnicode_InternFromString(name
);
582 if (descr
->d_name
== NULL
) {
591 PyDescr_NewMethod(PyTypeObject
*type
, PyMethodDef
*method
)
593 PyMethodDescrObject
*descr
;
595 descr
= (PyMethodDescrObject
*)descr_new(&PyMethodDescr_Type
,
596 type
, method
->ml_name
);
598 descr
->d_method
= method
;
599 return (PyObject
*)descr
;
603 PyDescr_NewClassMethod(PyTypeObject
*type
, PyMethodDef
*method
)
605 PyMethodDescrObject
*descr
;
607 descr
= (PyMethodDescrObject
*)descr_new(&PyClassMethodDescr_Type
,
608 type
, method
->ml_name
);
610 descr
->d_method
= method
;
611 return (PyObject
*)descr
;
615 PyDescr_NewMember(PyTypeObject
*type
, PyMemberDef
*member
)
617 PyMemberDescrObject
*descr
;
619 descr
= (PyMemberDescrObject
*)descr_new(&PyMemberDescr_Type
,
622 descr
->d_member
= member
;
623 return (PyObject
*)descr
;
627 PyDescr_NewGetSet(PyTypeObject
*type
, PyGetSetDef
*getset
)
629 PyGetSetDescrObject
*descr
;
631 descr
= (PyGetSetDescrObject
*)descr_new(&PyGetSetDescr_Type
,
634 descr
->d_getset
= getset
;
635 return (PyObject
*)descr
;
639 PyDescr_NewWrapper(PyTypeObject
*type
, struct wrapperbase
*base
, void *wrapped
)
641 PyWrapperDescrObject
*descr
;
643 descr
= (PyWrapperDescrObject
*)descr_new(&PyWrapperDescr_Type
,
646 descr
->d_base
= base
;
647 descr
->d_wrapped
= wrapped
;
649 return (PyObject
*)descr
;
653 /* --- Readonly proxy for dictionaries (actually any mapping) --- */
655 /* This has no reason to be in this file except that adding new files is a
664 proxy_len(proxyobject
*pp
)
666 return PyObject_Size(pp
->dict
);
670 proxy_getitem(proxyobject
*pp
, PyObject
*key
)
672 return PyObject_GetItem(pp
->dict
, key
);
675 static PyMappingMethods proxy_as_mapping
= {
676 (lenfunc
)proxy_len
, /* mp_length */
677 (binaryfunc
)proxy_getitem
, /* mp_subscript */
678 0, /* mp_ass_subscript */
682 proxy_contains(proxyobject
*pp
, PyObject
*key
)
684 return PyDict_Contains(pp
->dict
, key
);
687 static PySequenceMethods proxy_as_sequence
= {
694 0, /* sq_ass_slice */
695 (objobjproc
)proxy_contains
, /* sq_contains */
696 0, /* sq_inplace_concat */
697 0, /* sq_inplace_repeat */
701 proxy_get(proxyobject
*pp
, PyObject
*args
)
703 PyObject
*key
, *def
= Py_None
;
705 if (!PyArg_UnpackTuple(args
, "get", 1, 2, &key
, &def
))
707 return PyObject_CallMethod(pp
->dict
, "get", "(OO)", key
, def
);
711 proxy_keys(proxyobject
*pp
)
713 return PyMapping_Keys(pp
->dict
);
717 proxy_values(proxyobject
*pp
)
719 return PyMapping_Values(pp
->dict
);
723 proxy_items(proxyobject
*pp
)
725 return PyMapping_Items(pp
->dict
);
729 proxy_copy(proxyobject
*pp
)
731 return PyObject_CallMethod(pp
->dict
, "copy", NULL
);
734 static PyMethodDef proxy_methods
[] = {
735 {"get", (PyCFunction
)proxy_get
, METH_VARARGS
,
736 PyDoc_STR("D.get(k[,d]) -> D[k] if k in D, else d."
737 " d defaults to None.")},
738 {"keys", (PyCFunction
)proxy_keys
, METH_NOARGS
,
739 PyDoc_STR("D.keys() -> list of D's keys")},
740 {"values", (PyCFunction
)proxy_values
, METH_NOARGS
,
741 PyDoc_STR("D.values() -> list of D's values")},
742 {"items", (PyCFunction
)proxy_items
, METH_NOARGS
,
743 PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")},
744 {"copy", (PyCFunction
)proxy_copy
, METH_NOARGS
,
745 PyDoc_STR("D.copy() -> a shallow copy of D")},
750 proxy_dealloc(proxyobject
*pp
)
752 _PyObject_GC_UNTRACK(pp
);
758 proxy_getiter(proxyobject
*pp
)
760 return PyObject_GetIter(pp
->dict
);
764 proxy_str(proxyobject
*pp
)
766 return PyObject_Str(pp
->dict
);
770 proxy_traverse(PyObject
*self
, visitproc visit
, void *arg
)
772 proxyobject
*pp
= (proxyobject
*)self
;
778 proxy_richcompare(proxyobject
*v
, PyObject
*w
, int op
)
780 return PyObject_RichCompare(v
->dict
, w
, op
);
783 PyTypeObject PyDictProxy_Type
= {
784 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
785 "dict_proxy", /* tp_name */
786 sizeof(proxyobject
), /* tp_basicsize */
789 (destructor
)proxy_dealloc
, /* tp_dealloc */
795 0, /* tp_as_number */
796 &proxy_as_sequence
, /* tp_as_sequence */
797 &proxy_as_mapping
, /* tp_as_mapping */
800 (reprfunc
)proxy_str
, /* tp_str */
801 PyObject_GenericGetAttr
, /* tp_getattro */
803 0, /* tp_as_buffer */
804 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
806 proxy_traverse
, /* tp_traverse */
808 (richcmpfunc
)proxy_richcompare
, /* tp_richcompare */
809 0, /* tp_weaklistoffset */
810 (getiterfunc
)proxy_getiter
, /* tp_iter */
812 proxy_methods
, /* tp_methods */
817 0, /* tp_descr_get */
818 0, /* tp_descr_set */
822 PyDictProxy_New(PyObject
*dict
)
826 pp
= PyObject_GC_New(proxyobject
, &PyDictProxy_Type
);
830 _PyObject_GC_TRACK(pp
);
832 return (PyObject
*)pp
;
836 /* --- Wrapper object for "slot" methods --- */
838 /* This has no reason to be in this file except that adding new files is a
842 static PyTypeObject wrappertype
;
846 PyWrapperDescrObject
*descr
;
850 #define Wrapper_Check(v) (Py_TYPE(v) == &wrappertype)
853 wrapper_dealloc(wrapperobject
*wp
)
855 PyObject_GC_UnTrack(wp
);
856 Py_TRASHCAN_SAFE_BEGIN(wp
)
857 Py_XDECREF(wp
->descr
);
858 Py_XDECREF(wp
->self
);
860 Py_TRASHCAN_SAFE_END(wp
)
863 #define TEST_COND(cond) ((cond) ? Py_True : Py_False)
866 wrapper_richcompare(PyObject
*a
, PyObject
*b
, int op
)
870 PyWrapperDescrObject
*a_descr
, *b_descr
;
872 assert(a
!= NULL
&& b
!= NULL
);
874 /* both arguments should be wrapperobjects */
875 if (!Wrapper_Check(a
) || !Wrapper_Check(b
)) {
876 v
= Py_NotImplemented
;
881 /* compare by descriptor address; if the descriptors are the same,
882 compare by the objects they're bound to */
883 a_descr
= ((wrapperobject
*)a
)->descr
;
884 b_descr
= ((wrapperobject
*)b
)->descr
;
885 if (a_descr
== b_descr
) {
886 a
= ((wrapperobject
*)a
)->self
;
887 b
= ((wrapperobject
*)b
)->self
;
888 return PyObject_RichCompare(a
, b
, op
);
891 result
= a_descr
- b_descr
;
894 v
= TEST_COND(result
== 0);
897 v
= TEST_COND(result
!= 0);
900 v
= TEST_COND(result
<= 0);
903 v
= TEST_COND(result
>= 0);
906 v
= TEST_COND(result
< 0);
909 v
= TEST_COND(result
> 0);
920 wrapper_hash(wrapperobject
*wp
)
923 x
= _Py_HashPointer(wp
->descr
);
926 y
= PyObject_Hash(wp
->self
);
936 wrapper_repr(wrapperobject
*wp
)
938 return PyUnicode_FromFormat("<method-wrapper '%s' of %s object at %p>",
939 wp
->descr
->d_base
->name
,
940 wp
->self
->ob_type
->tp_name
,
944 static PyMemberDef wrapper_members
[] = {
945 {"__self__", T_OBJECT
, offsetof(wrapperobject
, self
), READONLY
},
950 wrapper_objclass(wrapperobject
*wp
)
952 PyObject
*c
= (PyObject
*)wp
->descr
->d_type
;
959 wrapper_name(wrapperobject
*wp
)
961 const char *s
= wp
->descr
->d_base
->name
;
963 return PyUnicode_FromString(s
);
967 wrapper_doc(wrapperobject
*wp
)
969 const char *s
= wp
->descr
->d_base
->doc
;
976 return PyUnicode_FromString(s
);
980 static PyGetSetDef wrapper_getsets
[] = {
981 {"__objclass__", (getter
)wrapper_objclass
},
982 {"__name__", (getter
)wrapper_name
},
983 {"__doc__", (getter
)wrapper_doc
},
988 wrapper_call(wrapperobject
*wp
, PyObject
*args
, PyObject
*kwds
)
990 wrapperfunc wrapper
= wp
->descr
->d_base
->wrapper
;
991 PyObject
*self
= wp
->self
;
993 if (wp
->descr
->d_base
->flags
& PyWrapperFlag_KEYWORDS
) {
994 wrapperfunc_kwds wk
= (wrapperfunc_kwds
)wrapper
;
995 return (*wk
)(self
, args
, wp
->descr
->d_wrapped
, kwds
);
998 if (kwds
!= NULL
&& (!PyDict_Check(kwds
) || PyDict_Size(kwds
) != 0)) {
999 PyErr_Format(PyExc_TypeError
,
1000 "wrapper %s doesn't take keyword arguments",
1001 wp
->descr
->d_base
->name
);
1004 return (*wrapper
)(self
, args
, wp
->descr
->d_wrapped
);
1008 wrapper_traverse(PyObject
*self
, visitproc visit
, void *arg
)
1010 wrapperobject
*wp
= (wrapperobject
*)self
;
1011 Py_VISIT(wp
->descr
);
1016 static PyTypeObject wrappertype
= {
1017 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
1018 "method-wrapper", /* tp_name */
1019 sizeof(wrapperobject
), /* tp_basicsize */
1020 0, /* tp_itemsize */
1022 (destructor
)wrapper_dealloc
, /* tp_dealloc */
1026 0, /* tp_reserved */
1027 (reprfunc
)wrapper_repr
, /* tp_repr */
1028 0, /* tp_as_number */
1029 0, /* tp_as_sequence */
1030 0, /* tp_as_mapping */
1031 (hashfunc
)wrapper_hash
, /* tp_hash */
1032 (ternaryfunc
)wrapper_call
, /* tp_call */
1034 PyObject_GenericGetAttr
, /* tp_getattro */
1035 0, /* tp_setattro */
1036 0, /* tp_as_buffer */
1037 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
, /* tp_flags */
1039 wrapper_traverse
, /* tp_traverse */
1041 wrapper_richcompare
, /* tp_richcompare */
1042 0, /* tp_weaklistoffset */
1044 0, /* tp_iternext */
1046 wrapper_members
, /* tp_members */
1047 wrapper_getsets
, /* tp_getset */
1050 0, /* tp_descr_get */
1051 0, /* tp_descr_set */
1055 PyWrapper_New(PyObject
*d
, PyObject
*self
)
1058 PyWrapperDescrObject
*descr
;
1060 assert(PyObject_TypeCheck(d
, &PyWrapperDescr_Type
));
1061 descr
= (PyWrapperDescrObject
*)d
;
1062 assert(PyObject_IsInstance(self
, (PyObject
*)(descr
->d_type
)));
1064 wp
= PyObject_GC_New(wrapperobject
, &wrappertype
);
1070 _PyObject_GC_TRACK(wp
);
1072 return (PyObject
*)wp
;
1076 /* A built-in 'property' type */
1079 class property(object):
1081 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
1082 if doc is None and fget is not None and hasattr(fget, "__doc__"):
1089 def __get__(self, inst, type=None):
1092 if self.__get is None:
1093 raise AttributeError, "unreadable attribute"
1094 return self.__get(inst)
1096 def __set__(self, inst, value):
1097 if self.__set is None:
1098 raise AttributeError, "can't set attribute"
1099 return self.__set(inst, value)
1101 def __delete__(self, inst):
1102 if self.__del is None:
1103 raise AttributeError, "can't delete attribute"
1104 return self.__del(inst)
1117 static PyObject
* property_copy(PyObject
*, PyObject
*, PyObject
*,
1118 PyObject
*, PyObject
*);
1120 static PyMemberDef property_members
[] = {
1121 {"fget", T_OBJECT
, offsetof(propertyobject
, prop_get
), READONLY
},
1122 {"fset", T_OBJECT
, offsetof(propertyobject
, prop_set
), READONLY
},
1123 {"fdel", T_OBJECT
, offsetof(propertyobject
, prop_del
), READONLY
},
1124 {"__doc__", T_OBJECT
, offsetof(propertyobject
, prop_doc
), READONLY
},
1129 PyDoc_STRVAR(getter_doc
,
1130 "Descriptor to change the getter on a property.");
1133 property_getter(PyObject
*self
, PyObject
*getter
)
1135 return property_copy(self
, getter
, NULL
, NULL
, NULL
);
1139 PyDoc_STRVAR(setter_doc
,
1140 "Descriptor to change the setter on a property.");
1143 property_setter(PyObject
*self
, PyObject
*setter
)
1145 return property_copy(self
, NULL
, setter
, NULL
, NULL
);
1149 PyDoc_STRVAR(deleter_doc
,
1150 "Descriptor to change the deleter on a property.");
1153 property_deleter(PyObject
*self
, PyObject
*deleter
)
1155 return property_copy(self
, NULL
, NULL
, deleter
, NULL
);
1159 static PyMethodDef property_methods
[] = {
1160 {"getter", property_getter
, METH_O
, getter_doc
},
1161 {"setter", property_setter
, METH_O
, setter_doc
},
1162 {"deleter", property_deleter
, METH_O
, deleter_doc
},
1168 property_dealloc(PyObject
*self
)
1170 propertyobject
*gs
= (propertyobject
*)self
;
1172 _PyObject_GC_UNTRACK(self
);
1173 Py_XDECREF(gs
->prop_get
);
1174 Py_XDECREF(gs
->prop_set
);
1175 Py_XDECREF(gs
->prop_del
);
1176 Py_XDECREF(gs
->prop_doc
);
1177 self
->ob_type
->tp_free(self
);
1181 property_descr_get(PyObject
*self
, PyObject
*obj
, PyObject
*type
)
1183 propertyobject
*gs
= (propertyobject
*)self
;
1185 if (obj
== NULL
|| obj
== Py_None
) {
1189 if (gs
->prop_get
== NULL
) {
1190 PyErr_SetString(PyExc_AttributeError
, "unreadable attribute");
1193 return PyObject_CallFunction(gs
->prop_get
, "(O)", obj
);
1197 property_descr_set(PyObject
*self
, PyObject
*obj
, PyObject
*value
)
1199 propertyobject
*gs
= (propertyobject
*)self
;
1200 PyObject
*func
, *res
;
1203 func
= gs
->prop_del
;
1205 func
= gs
->prop_set
;
1207 PyErr_SetString(PyExc_AttributeError
,
1209 "can't delete attribute" :
1210 "can't set attribute");
1214 res
= PyObject_CallFunction(func
, "(O)", obj
);
1216 res
= PyObject_CallFunction(func
, "(OO)", obj
, value
);
1224 property_copy(PyObject
*old
, PyObject
*get
, PyObject
*set
, PyObject
*del
,
1227 propertyobject
*pold
= (propertyobject
*)old
;
1228 PyObject
*new, *type
;
1230 type
= PyObject_Type(old
);
1234 if (get
== NULL
|| get
== Py_None
) {
1236 get
= pold
->prop_get
? pold
->prop_get
: Py_None
;
1238 if (set
== NULL
|| set
== Py_None
) {
1240 set
= pold
->prop_set
? pold
->prop_set
: Py_None
;
1242 if (del
== NULL
|| del
== Py_None
) {
1244 del
= pold
->prop_del
? pold
->prop_del
: Py_None
;
1246 if (doc
== NULL
|| doc
== Py_None
) {
1248 if (pold
->getter_doc
&& get
!= Py_None
) {
1249 /* make _init use __doc__ from getter */
1253 doc
= pold
->prop_doc
? pold
->prop_doc
: Py_None
;
1257 new = PyObject_CallFunction(type
, "OOOO", get
, set
, del
, doc
);
1265 property_init(PyObject
*self
, PyObject
*args
, PyObject
*kwds
)
1267 PyObject
*get
= NULL
, *set
= NULL
, *del
= NULL
, *doc
= NULL
;
1268 static char *kwlist
[] = {"fget", "fset", "fdel", "doc", 0};
1269 propertyobject
*prop
= (propertyobject
*)self
;
1271 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "|OOOO:property",
1272 kwlist
, &get
, &set
, &del
, &doc
))
1287 prop
->prop_get
= get
;
1288 prop
->prop_set
= set
;
1289 prop
->prop_del
= del
;
1290 prop
->prop_doc
= doc
;
1291 prop
->getter_doc
= 0;
1293 /* if no docstring given and the getter has one, use that one */
1294 if ((doc
== NULL
|| doc
== Py_None
) && get
!= NULL
) {
1295 PyObject
*get_doc
= PyObject_GetAttrString(get
, "__doc__");
1297 if (Py_TYPE(self
) == &PyProperty_Type
) {
1298 Py_XDECREF(prop
->prop_doc
);
1299 prop
->prop_doc
= get_doc
;
1302 /* If this is a property subclass, put __doc__
1303 in dict of the subclass instance instead,
1304 otherwise it gets shadowed by __doc__ in the
1306 int err
= PyObject_SetAttrString(self
, "__doc__", get_doc
);
1311 prop
->getter_doc
= 1;
1313 else if (PyErr_ExceptionMatches(PyExc_Exception
)) {
1324 PyDoc_STRVAR(property_doc
,
1325 "property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n"
1327 "fget is a function to be used for getting an attribute value, and likewise\n"
1328 "fset is a function for setting, and fdel a function for del'ing, an\n"
1329 "attribute. Typical use is to define a managed attribute x:\n"
1330 "class C(object):\n"
1331 " def getx(self): return self._x\n"
1332 " def setx(self, value): self._x = value\n"
1333 " def delx(self): del self._x\n"
1334 " x = property(getx, setx, delx, \"I'm the 'x' property.\")\n"
1336 "Decorators make defining new properties or modifying existing ones easy:\n"
1337 "class C(object):\n"
1339 " def x(self): return self._x\n"
1341 " def x(self, value): self._x = value\n"
1343 " def x(self): del self._x\n"
1347 property_traverse(PyObject
*self
, visitproc visit
, void *arg
)
1349 propertyobject
*pp
= (propertyobject
*)self
;
1350 Py_VISIT(pp
->prop_get
);
1351 Py_VISIT(pp
->prop_set
);
1352 Py_VISIT(pp
->prop_del
);
1353 Py_VISIT(pp
->prop_doc
);
1357 PyTypeObject PyProperty_Type
= {
1358 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
1359 "property", /* tp_name */
1360 sizeof(propertyobject
), /* tp_basicsize */
1361 0, /* tp_itemsize */
1363 property_dealloc
, /* tp_dealloc */
1367 0, /* tp_reserved */
1369 0, /* tp_as_number */
1370 0, /* tp_as_sequence */
1371 0, /* tp_as_mapping */
1375 PyObject_GenericGetAttr
, /* tp_getattro */
1376 0, /* tp_setattro */
1377 0, /* tp_as_buffer */
1378 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_GC
|
1379 Py_TPFLAGS_BASETYPE
, /* tp_flags */
1380 property_doc
, /* tp_doc */
1381 property_traverse
, /* tp_traverse */
1383 0, /* tp_richcompare */
1384 0, /* tp_weaklistoffset */
1386 0, /* tp_iternext */
1387 property_methods
, /* tp_methods */
1388 property_members
, /* tp_members */
1392 property_descr_get
, /* tp_descr_get */
1393 property_descr_set
, /* tp_descr_set */
1394 0, /* tp_dictoffset */
1395 property_init
, /* tp_init */
1396 PyType_GenericAlloc
, /* tp_alloc */
1397 PyType_GenericNew
, /* tp_new */
1398 PyObject_GC_Del
, /* tp_free */