Update for release.
[python/dscho.git] / Objects / descrobject.c
blob6c78778fd593e7861ac017073a77268d930f0ac7
1 /* Descriptors -- a new, flexible way to describe attributes */
3 #include "Python.h"
4 #include "structmember.h" /* Why is this not included in Python.h? */
6 static void
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);
15 static char *
16 descr_name(PyDescrObject *descr)
18 if (descr->d_name != NULL && PyString_Check(descr->d_name))
19 return PyString_AS_STRING(descr->d_name);
20 else
21 return "?";
24 static PyObject *
25 descr_repr(PyDescrObject *descr, char *format)
27 return PyString_FromFormat(format, descr_name(descr),
28 descr->d_type->tp_name);
31 static PyObject *
32 method_repr(PyMethodDescrObject *descr)
34 return descr_repr((PyDescrObject *)descr,
35 "<method '%s' of '%s' objects>");
38 static PyObject *
39 member_repr(PyMemberDescrObject *descr)
41 return descr_repr((PyDescrObject *)descr,
42 "<member '%s' of '%s' objects>");
45 static PyObject *
46 getset_repr(PyGetSetDescrObject *descr)
48 return descr_repr((PyDescrObject *)descr,
49 "<attribute '%s' of '%s' objects>");
52 static PyObject *
53 wrapper_repr(PyWrapperDescrObject *descr)
55 return descr_repr((PyDescrObject *)descr,
56 "<slot wrapper '%s' of '%s' objects>");
59 static int
60 descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
61 PyObject **pres)
63 if (obj == NULL || (obj == Py_None && type != Py_None->ob_type)) {
64 Py_INCREF(descr);
65 *pres = (PyObject *)descr;
66 return 1;
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);
75 *pres = NULL;
76 return 1;
78 return 0;
81 static PyObject *
82 classmethod_get(PyMethodDescrObject *descr, PyObject *obj,
83 PyTypeObject *type)
85 return PyCFunction_New(descr->d_method, (PyObject *)type);
88 static PyObject *
89 method_get(PyMethodDescrObject *descr, PyObject *obj, PyTypeObject *type)
91 PyObject *res;
93 if (descr_check((PyDescrObject *)descr, obj, type, &res))
94 return res;
95 return PyCFunction_New(descr->d_method, obj);
98 static PyObject *
99 member_get(PyMemberDescrObject *descr, PyObject *obj, PyTypeObject *type)
101 PyObject *res;
103 if (descr_check((PyDescrObject *)descr, obj, type, &res))
104 return res;
105 return PyMember_GetOne((char *)obj, descr->d_member);
108 static PyObject *
109 getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
111 PyObject *res;
113 if (descr_check((PyDescrObject *)descr, obj, type, &res))
114 return 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);
121 return NULL;
124 static PyObject *
125 wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyTypeObject *type)
127 PyObject *res;
129 if (descr_check((PyDescrObject *)descr, obj, type, &res))
130 return res;
131 return PyWrapper_New((PyObject *)descr, obj);
134 static int
135 descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,
136 int *pres)
138 assert(obj != NULL);
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",
143 descr_name(descr),
144 descr->d_type->tp_name,
145 obj->ob_type->tp_name);
146 *pres = -1;
147 return 1;
149 return 0;
152 static int
153 member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)
155 int res;
157 if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
158 return res;
159 return PyMember_SetOne((char *)obj, descr->d_member, value);
162 static int
163 getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
165 int res;
167 if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
168 return 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);
176 return -1;
179 static PyObject *
180 methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
182 int argc;
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);
188 if (argc < 1) {
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);
194 return NULL;
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);
205 return NULL;
208 func = PyCFunction_New(descr->d_method, self);
209 if (func == NULL)
210 return NULL;
211 args = PyTuple_GetSlice(args, 1, argc);
212 if (args == NULL) {
213 Py_DECREF(func);
214 return NULL;
216 result = PyEval_CallObjectWithKeywords(func, args, kwds);
217 Py_DECREF(args);
218 Py_DECREF(func);
219 return result;
222 static PyObject *
223 classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
224 PyObject *kwds)
226 PyObject *func, *result;
228 func = PyCFunction_New(descr->d_method, (PyObject *)descr->d_type);
229 if (func == NULL)
230 return NULL;
232 result = PyEval_CallObjectWithKeywords(func, args, kwds);
233 Py_DECREF(func);
234 return result;
237 static PyObject *
238 wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
240 int argc;
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);
246 if (argc < 1) {
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);
252 return NULL;
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);
263 return NULL;
266 func = PyWrapper_New((PyObject *)descr, self);
267 if (func == NULL)
268 return NULL;
269 args = PyTuple_GetSlice(args, 1, argc);
270 if (args == NULL) {
271 Py_DECREF(func);
272 return NULL;
274 result = PyEval_CallObjectWithKeywords(func, args, kwds);
275 Py_DECREF(args);
276 Py_DECREF(func);
277 return result;
280 static PyObject *
281 method_get_doc(PyMethodDescrObject *descr, void *closure)
283 if (descr->d_method->ml_doc == NULL) {
284 Py_INCREF(Py_None);
285 return Py_None;
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},
301 static PyObject *
302 member_get_doc(PyMemberDescrObject *descr, void *closure)
304 if (descr->d_member->doc == NULL) {
305 Py_INCREF(Py_None);
306 return Py_None;
308 return PyString_FromString(descr->d_member->doc);
311 static PyGetSetDef member_getset[] = {
312 {"__doc__", (getter)member_get_doc},
316 static PyObject *
317 getset_get_doc(PyGetSetDescrObject *descr, void *closure)
319 if (descr->d_getset->doc == NULL) {
320 Py_INCREF(Py_None);
321 return Py_None;
323 return PyString_FromString(descr->d_getset->doc);
326 static PyGetSetDef getset_getset[] = {
327 {"__doc__", (getter)getset_get_doc},
331 static PyObject *
332 wrapper_get_doc(PyWrapperDescrObject *descr, void *closure)
334 if (descr->d_base->doc == NULL) {
335 Py_INCREF(Py_None);
336 return Py_None;
338 return PyString_FromString(descr->d_base->doc);
341 static PyGetSetDef wrapper_getset[] = {
342 {"__doc__", (getter)wrapper_get_doc},
346 static int
347 descr_traverse(PyObject *self, visitproc visit, void *arg)
349 PyDescrObject *descr = (PyDescrObject *)self;
350 int err;
352 if (descr->d_type) {
353 err = visit((PyObject *)(descr->d_type), arg);
354 if (err)
355 return err;
357 return 0;
360 static PyTypeObject PyMethodDescr_Type = {
361 PyObject_HEAD_INIT(&PyType_Type)
363 "method_descriptor",
364 sizeof(PyMethodDescrObject),
366 (destructor)descr_dealloc, /* tp_dealloc */
367 0, /* tp_print */
368 0, /* tp_getattr */
369 0, /* tp_setattr */
370 0, /* tp_compare */
371 (reprfunc)method_repr, /* tp_repr */
372 0, /* tp_as_number */
373 0, /* tp_as_sequence */
374 0, /* tp_as_mapping */
375 0, /* tp_hash */
376 (ternaryfunc)methoddescr_call, /* tp_call */
377 0, /* tp_str */
378 PyObject_GenericGetAttr, /* tp_getattro */
379 0, /* tp_setattro */
380 0, /* tp_as_buffer */
381 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
382 0, /* tp_doc */
383 descr_traverse, /* tp_traverse */
384 0, /* tp_clear */
385 0, /* tp_richcompare */
386 0, /* tp_weaklistoffset */
387 0, /* tp_iter */
388 0, /* tp_iternext */
389 0, /* tp_methods */
390 descr_members, /* tp_members */
391 method_getset, /* tp_getset */
392 0, /* tp_base */
393 0, /* tp_dict */
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 */
405 0, /* tp_print */
406 0, /* tp_getattr */
407 0, /* tp_setattr */
408 0, /* tp_compare */
409 (reprfunc)method_repr, /* tp_repr */
410 0, /* tp_as_number */
411 0, /* tp_as_sequence */
412 0, /* tp_as_mapping */
413 0, /* tp_hash */
414 (ternaryfunc)classmethoddescr_call, /* tp_call */
415 0, /* tp_str */
416 PyObject_GenericGetAttr, /* tp_getattro */
417 0, /* tp_setattro */
418 0, /* tp_as_buffer */
419 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
420 0, /* tp_doc */
421 descr_traverse, /* tp_traverse */
422 0, /* tp_clear */
423 0, /* tp_richcompare */
424 0, /* tp_weaklistoffset */
425 0, /* tp_iter */
426 0, /* tp_iternext */
427 0, /* tp_methods */
428 descr_members, /* tp_members */
429 method_getset, /* tp_getset */
430 0, /* tp_base */
431 0, /* tp_dict */
432 (descrgetfunc)classmethod_get, /* tp_descr_get */
433 0, /* tp_descr_set */
436 static PyTypeObject PyMemberDescr_Type = {
437 PyObject_HEAD_INIT(&PyType_Type)
439 "member_descriptor",
440 sizeof(PyMemberDescrObject),
442 (destructor)descr_dealloc, /* tp_dealloc */
443 0, /* tp_print */
444 0, /* tp_getattr */
445 0, /* tp_setattr */
446 0, /* tp_compare */
447 (reprfunc)member_repr, /* tp_repr */
448 0, /* tp_as_number */
449 0, /* tp_as_sequence */
450 0, /* tp_as_mapping */
451 0, /* tp_hash */
452 (ternaryfunc)0, /* tp_call */
453 0, /* tp_str */
454 PyObject_GenericGetAttr, /* tp_getattro */
455 0, /* tp_setattro */
456 0, /* tp_as_buffer */
457 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
458 0, /* tp_doc */
459 descr_traverse, /* tp_traverse */
460 0, /* tp_clear */
461 0, /* tp_richcompare */
462 0, /* tp_weaklistoffset */
463 0, /* tp_iter */
464 0, /* tp_iternext */
465 0, /* tp_methods */
466 descr_members, /* tp_members */
467 member_getset, /* tp_getset */
468 0, /* tp_base */
469 0, /* tp_dict */
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)
477 "getset_descriptor",
478 sizeof(PyGetSetDescrObject),
480 (destructor)descr_dealloc, /* tp_dealloc */
481 0, /* tp_print */
482 0, /* tp_getattr */
483 0, /* tp_setattr */
484 0, /* tp_compare */
485 (reprfunc)getset_repr, /* tp_repr */
486 0, /* tp_as_number */
487 0, /* tp_as_sequence */
488 0, /* tp_as_mapping */
489 0, /* tp_hash */
490 (ternaryfunc)0, /* tp_call */
491 0, /* tp_str */
492 PyObject_GenericGetAttr, /* tp_getattro */
493 0, /* tp_setattro */
494 0, /* tp_as_buffer */
495 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
496 0, /* tp_doc */
497 descr_traverse, /* tp_traverse */
498 0, /* tp_clear */
499 0, /* tp_richcompare */
500 0, /* tp_weaklistoffset */
501 0, /* tp_iter */
502 0, /* tp_iternext */
503 0, /* tp_methods */
504 descr_members, /* tp_members */
505 getset_getset, /* tp_getset */
506 0, /* tp_base */
507 0, /* tp_dict */
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 */
519 0, /* tp_print */
520 0, /* tp_getattr */
521 0, /* tp_setattr */
522 0, /* tp_compare */
523 (reprfunc)wrapper_repr, /* tp_repr */
524 0, /* tp_as_number */
525 0, /* tp_as_sequence */
526 0, /* tp_as_mapping */
527 0, /* tp_hash */
528 (ternaryfunc)wrapperdescr_call, /* tp_call */
529 0, /* tp_str */
530 PyObject_GenericGetAttr, /* tp_getattro */
531 0, /* tp_setattro */
532 0, /* tp_as_buffer */
533 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
534 0, /* tp_doc */
535 descr_traverse, /* tp_traverse */
536 0, /* tp_clear */
537 0, /* tp_richcompare */
538 0, /* tp_weaklistoffset */
539 0, /* tp_iter */
540 0, /* tp_iternext */
541 0, /* tp_methods */
542 descr_members, /* tp_members */
543 wrapper_getset, /* tp_getset */
544 0, /* tp_base */
545 0, /* tp_dict */
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);
556 if (descr != NULL) {
557 Py_XINCREF(type);
558 descr->d_type = type;
559 descr->d_name = PyString_InternFromString(name);
560 if (descr->d_name == NULL) {
561 Py_DECREF(descr);
562 descr = NULL;
565 return descr;
568 PyObject *
569 PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
571 PyMethodDescrObject *descr;
573 descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
574 type, method->ml_name);
575 if (descr != NULL)
576 descr->d_method = method;
577 return (PyObject *)descr;
580 PyObject *
581 PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)
583 PyMethodDescrObject *descr;
585 descr = (PyMethodDescrObject *)descr_new(&PyClassMethodDescr_Type,
586 type, method->ml_name);
587 if (descr != NULL)
588 descr->d_method = method;
589 return (PyObject *)descr;
592 PyObject *
593 PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member)
595 PyMemberDescrObject *descr;
597 descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,
598 type, member->name);
599 if (descr != NULL)
600 descr->d_member = member;
601 return (PyObject *)descr;
604 PyObject *
605 PyDescr_NewGetSet(PyTypeObject *type, PyGetSetDef *getset)
607 PyGetSetDescrObject *descr;
609 descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
610 type, getset->name);
611 if (descr != NULL)
612 descr->d_getset = getset;
613 return (PyObject *)descr;
616 PyObject *
617 PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
619 PyWrapperDescrObject *descr;
621 descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
622 type, base->name);
623 if (descr != NULL) {
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
634 bit of a pain */
636 typedef struct {
637 PyObject_HEAD
638 PyObject *dict;
639 } proxyobject;
641 static int
642 proxy_len(proxyobject *pp)
644 return PyObject_Size(pp->dict);
647 static PyObject *
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 */
659 static int
660 proxy_contains(proxyobject *pp, PyObject *key)
662 return PySequence_Contains(pp->dict, key);
665 static PySequenceMethods proxy_as_sequence = {
666 0, /* sq_length */
667 0, /* sq_concat */
668 0, /* sq_repeat */
669 0, /* sq_item */
670 0, /* sq_slice */
671 0, /* sq_ass_item */
672 0, /* sq_ass_slice */
673 (objobjproc)proxy_contains, /* sq_contains */
674 0, /* sq_inplace_concat */
675 0, /* sq_inplace_repeat */
678 static PyObject *
679 proxy_has_key(proxyobject *pp, PyObject *key)
681 return PyInt_FromLong(PySequence_Contains(pp->dict, key));
684 static PyObject *
685 proxy_get(proxyobject *pp, PyObject *args)
687 PyObject *key, *def = Py_None;
689 if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def))
690 return NULL;
691 return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
694 static PyObject *
695 proxy_keys(proxyobject *pp)
697 return PyMapping_Keys(pp->dict);
700 static PyObject *
701 proxy_values(proxyobject *pp)
703 return PyMapping_Values(pp->dict);
706 static PyObject *
707 proxy_items(proxyobject *pp)
709 return PyMapping_Items(pp->dict);
712 static PyObject *
713 proxy_iterkeys(proxyobject *pp)
715 return PyObject_CallMethod(pp->dict, "iterkeys", NULL);
718 static PyObject *
719 proxy_itervalues(proxyobject *pp)
721 return PyObject_CallMethod(pp->dict, "itervalues", NULL);
724 static PyObject *
725 proxy_iteritems(proxyobject *pp)
727 return PyObject_CallMethod(pp->dict, "iteritems", NULL);
729 static PyObject *
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")},
759 static void
760 proxy_dealloc(proxyobject *pp)
762 _PyObject_GC_UNTRACK(pp);
763 Py_DECREF(pp->dict);
764 PyObject_GC_Del(pp);
767 static PyObject *
768 proxy_getiter(proxyobject *pp)
770 return PyObject_GetIter(pp->dict);
773 static PyObject *
774 proxy_str(proxyobject *pp)
776 return PyObject_Str(pp->dict);
779 static int
780 proxy_traverse(PyObject *self, visitproc visit, void *arg)
782 proxyobject *pp = (proxyobject *)self;
783 int err;
785 if (pp->dict) {
786 err = visit(pp->dict, arg);
787 if (err)
788 return err;
790 return 0;
793 static int
794 proxy_compare(proxyobject *v, PyObject *w)
796 return PyObject_Compare(v->dict, w);
799 static PyObject *
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)
807 0, /* ob_size */
808 "dictproxy", /* tp_name */
809 sizeof(proxyobject), /* tp_basicsize */
810 0, /* tp_itemsize */
811 /* methods */
812 (destructor)proxy_dealloc, /* tp_dealloc */
813 0, /* tp_print */
814 0, /* tp_getattr */
815 0, /* tp_setattr */
816 (cmpfunc)proxy_compare, /* tp_compare */
817 0, /* tp_repr */
818 0, /* tp_as_number */
819 &proxy_as_sequence, /* tp_as_sequence */
820 &proxy_as_mapping, /* tp_as_mapping */
821 0, /* tp_hash */
822 0, /* tp_call */
823 (reprfunc)proxy_str, /* tp_str */
824 PyObject_GenericGetAttr, /* tp_getattro */
825 0, /* tp_setattro */
826 0, /* tp_as_buffer */
827 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
828 0, /* tp_doc */
829 proxy_traverse, /* tp_traverse */
830 0, /* tp_clear */
831 (richcmpfunc)proxy_richcompare, /* tp_richcompare */
832 0, /* tp_weaklistoffset */
833 (getiterfunc)proxy_getiter, /* tp_iter */
834 0, /* tp_iternext */
835 proxy_methods, /* tp_methods */
836 0, /* tp_members */
837 0, /* tp_getset */
838 0, /* tp_base */
839 0, /* tp_dict */
840 0, /* tp_descr_get */
841 0, /* tp_descr_set */
844 PyObject *
845 PyDictProxy_New(PyObject *dict)
847 proxyobject *pp;
849 pp = PyObject_GC_New(proxyobject, &proxytype);
850 if (pp != NULL) {
851 Py_INCREF(dict);
852 pp->dict = dict;
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
862 bit of a pain */
864 typedef struct {
865 PyObject_HEAD
866 PyWrapperDescrObject *descr;
867 PyObject *self;
868 } wrapperobject;
870 static void
871 wrapper_dealloc(wrapperobject *wp)
873 _PyObject_GC_UNTRACK(wp);
874 Py_XDECREF(wp->descr);
875 Py_XDECREF(wp->self);
876 PyObject_GC_Del(wp);
879 static PyMethodDef wrapper_methods[] = {
883 static PyObject *
884 wrapper_name(wrapperobject *wp)
886 char *s = wp->descr->d_base->name;
888 return PyString_FromString(s);
891 static PyObject *
892 wrapper_doc(wrapperobject *wp)
894 char *s = wp->descr->d_base->doc;
896 if (s == NULL) {
897 Py_INCREF(Py_None);
898 return Py_None;
900 else {
901 return PyString_FromString(s);
905 static PyGetSetDef wrapper_getsets[] = {
906 {"__name__", (getter)wrapper_name},
907 {"__doc__", (getter)wrapper_doc},
911 static PyObject *
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);
926 return NULL;
928 return (*wrapper)(self, args, wp->descr->d_wrapped);
931 static int
932 wrapper_traverse(PyObject *self, visitproc visit, void *arg)
934 wrapperobject *wp = (wrapperobject *)self;
935 int err;
937 if (wp->descr) {
938 err = visit((PyObject *)(wp->descr), arg);
939 if (err)
940 return err;
942 if (wp->self) {
943 err = visit(wp->self, arg);
944 if (err)
945 return err;
947 return 0;
950 static PyTypeObject wrappertype = {
951 PyObject_HEAD_INIT(&PyType_Type)
952 0, /* ob_size */
953 "method-wrapper", /* tp_name */
954 sizeof(wrapperobject), /* tp_basicsize */
955 0, /* tp_itemsize */
956 /* methods */
957 (destructor)wrapper_dealloc, /* tp_dealloc */
958 0, /* tp_print */
959 0, /* tp_getattr */
960 0, /* tp_setattr */
961 0, /* tp_compare */
962 0, /* tp_repr */
963 0, /* tp_as_number */
964 0, /* tp_as_sequence */
965 0, /* tp_as_mapping */
966 0, /* tp_hash */
967 (ternaryfunc)wrapper_call, /* tp_call */
968 0, /* tp_str */
969 PyObject_GenericGetAttr, /* tp_getattro */
970 0, /* tp_setattro */
971 0, /* tp_as_buffer */
972 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
973 0, /* tp_doc */
974 wrapper_traverse, /* tp_traverse */
975 0, /* tp_clear */
976 0, /* tp_richcompare */
977 0, /* tp_weaklistoffset */
978 0, /* tp_iter */
979 0, /* tp_iternext */
980 wrapper_methods, /* tp_methods */
981 0, /* tp_members */
982 wrapper_getsets, /* tp_getset */
983 0, /* tp_base */
984 0, /* tp_dict */
985 0, /* tp_descr_get */
986 0, /* tp_descr_set */
989 PyObject *
990 PyWrapper_New(PyObject *d, PyObject *self)
992 wrapperobject *wp;
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);
1000 if (wp != NULL) {
1001 Py_INCREF(descr);
1002 wp->descr = descr;
1003 Py_INCREF(self);
1004 wp->self = self;
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):
1017 self.__get = fget
1018 self.__set = fset
1019 self.__del = fdel
1020 self.__doc__ = doc
1022 def __get__(self, inst, type=None):
1023 if inst is None:
1024 return self
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)
1041 typedef struct {
1042 PyObject_HEAD
1043 PyObject *prop_get;
1044 PyObject *prop_set;
1045 PyObject *prop_del;
1046 PyObject *prop_doc;
1047 } propertyobject;
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},
1058 static void
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);
1071 static PyObject *
1072 property_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1074 propertyobject *gs = (propertyobject *)self;
1076 if (obj == NULL || obj == Py_None) {
1077 Py_INCREF(self);
1078 return self;
1080 if (gs->prop_get == NULL) {
1081 PyErr_SetString(PyExc_AttributeError, "unreadable attribute");
1082 return NULL;
1084 return PyObject_CallFunction(gs->prop_get, "(O)", obj);
1087 static int
1088 property_descr_set(PyObject *self, PyObject *obj, PyObject *value)
1090 propertyobject *gs = (propertyobject *)self;
1091 PyObject *func, *res;
1093 if (value == NULL)
1094 func = gs->prop_del;
1095 else
1096 func = gs->prop_set;
1097 if (func == NULL) {
1098 PyErr_SetString(PyExc_AttributeError,
1099 value == NULL ?
1100 "can't delete attribute" :
1101 "can't set attribute");
1102 return -1;
1104 if (value == NULL)
1105 res = PyObject_CallFunction(func, "(O)", obj);
1106 else
1107 res = PyObject_CallFunction(func, "(OO)", obj, value);
1108 if (res == NULL)
1109 return -1;
1110 Py_DECREF(res);
1111 return 0;
1114 static int
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))
1123 return -1;
1125 if (get == Py_None)
1126 get = NULL;
1127 if (set == Py_None)
1128 set = NULL;
1129 if (del == Py_None)
1130 del = NULL;
1132 Py_XINCREF(get);
1133 Py_XINCREF(set);
1134 Py_XINCREF(del);
1135 Py_XINCREF(doc);
1137 gs->prop_get = get;
1138 gs->prop_set = set;
1139 gs->prop_del = del;
1140 gs->prop_doc = doc;
1142 return 0;
1145 PyDoc_STRVAR(property_doc,
1146 "property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n"
1147 "\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.\")");
1157 static int
1158 property_traverse(PyObject *self, visitproc visit, void *arg)
1160 propertyobject *pp = (propertyobject *)self;
1161 int err;
1163 #define VISIT(SLOT) \
1164 if (pp->SLOT) { \
1165 err = visit((PyObject *)(pp->SLOT), arg); \
1166 if (err) \
1167 return err; \
1170 VISIT(prop_get);
1171 VISIT(prop_set);
1172 VISIT(prop_del);
1174 return 0;
1177 PyTypeObject PyProperty_Type = {
1178 PyObject_HEAD_INIT(&PyType_Type)
1179 0, /* ob_size */
1180 "property", /* tp_name */
1181 sizeof(propertyobject), /* tp_basicsize */
1182 0, /* tp_itemsize */
1183 /* methods */
1184 property_dealloc, /* tp_dealloc */
1185 0, /* tp_print */
1186 0, /* tp_getattr */
1187 0, /* tp_setattr */
1188 0, /* tp_compare */
1189 0, /* tp_repr */
1190 0, /* tp_as_number */
1191 0, /* tp_as_sequence */
1192 0, /* tp_as_mapping */
1193 0, /* tp_hash */
1194 0, /* tp_call */
1195 0, /* tp_str */
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 */
1203 0, /* tp_clear */
1204 0, /* tp_richcompare */
1205 0, /* tp_weaklistoffset */
1206 0, /* tp_iter */
1207 0, /* tp_iternext */
1208 0, /* tp_methods */
1209 property_members, /* tp_members */
1210 0, /* tp_getset */
1211 0, /* tp_base */
1212 0, /* tp_dict */
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 */