blob: e5b08c375b032ddb55dcd5ed4a82c32f445da40a [file] [log] [blame]
Tim Peters6d6c1a32001-08-02 04:15:00 +00001/* Descriptors -- a new, flexible way to describe attributes */
2
3#include "Python.h"
4#include "structmember.h" /* Why is this not included in Python.h? */
5
6/* Various kinds of descriptor objects */
7
8#define COMMON \
9 PyObject_HEAD \
10 PyTypeObject *d_type; \
11 PyObject *d_name
12
13typedef struct {
14 COMMON;
15} PyDescrObject;
16
17typedef struct {
18 COMMON;
19 PyMethodDef *d_method;
20} PyMethodDescrObject;
21
22typedef struct {
23 COMMON;
24 struct memberlist *d_member;
25} PyMemberDescrObject;
26
27typedef struct {
28 COMMON;
29 struct getsetlist *d_getset;
30} PyGetSetDescrObject;
31
32typedef struct {
33 COMMON;
34 struct wrapperbase *d_base;
35 void *d_wrapped; /* This can be any function pointer */
36} PyWrapperDescrObject;
37
38static void
39descr_dealloc(PyDescrObject *descr)
40{
41 Py_XDECREF(descr->d_type);
42 Py_XDECREF(descr->d_name);
43 PyObject_DEL(descr);
44}
45
46static char *
47descr_name(PyDescrObject *descr)
48{
49 if (descr->d_name != NULL && PyString_Check(descr->d_name))
50 return PyString_AS_STRING(descr->d_name);
51 else
52 return "?";
53}
54
55static PyObject *
56descr_repr(PyDescrObject *descr, char *format)
57{
Barry Warsaw7ce36942001-08-24 18:34:26 +000058 return PyString_FromFormat(format, descr_name(descr),
59 descr->d_type->tp_name);
Tim Peters6d6c1a32001-08-02 04:15:00 +000060}
61
62static PyObject *
63method_repr(PyMethodDescrObject *descr)
64{
65 return descr_repr((PyDescrObject *)descr,
Barry Warsaw7ce36942001-08-24 18:34:26 +000066 "<method '%s' of '%s' objects>");
Tim Peters6d6c1a32001-08-02 04:15:00 +000067}
68
69static PyObject *
70member_repr(PyMemberDescrObject *descr)
71{
72 return descr_repr((PyDescrObject *)descr,
Barry Warsaw7ce36942001-08-24 18:34:26 +000073 "<member '%s' of '%s' objects>");
Tim Peters6d6c1a32001-08-02 04:15:00 +000074}
75
76static PyObject *
77getset_repr(PyGetSetDescrObject *descr)
78{
79 return descr_repr((PyDescrObject *)descr,
Barry Warsaw7ce36942001-08-24 18:34:26 +000080 "<attribute '%s' of '%s' objects>");
Tim Peters6d6c1a32001-08-02 04:15:00 +000081}
82
83static PyObject *
84wrapper_repr(PyWrapperDescrObject *descr)
85{
86 return descr_repr((PyDescrObject *)descr,
Barry Warsaw7ce36942001-08-24 18:34:26 +000087 "<slot wrapper '%s' of '%s' objects>");
Tim Peters6d6c1a32001-08-02 04:15:00 +000088}
89
90static int
91descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
Guido van Rossum8098ddb2001-08-16 08:27:33 +000092 PyObject **pres)
Tim Peters6d6c1a32001-08-02 04:15:00 +000093{
Guido van Rossum8098ddb2001-08-16 08:27:33 +000094 if (obj == NULL || (obj == Py_None && type != Py_None->ob_type)) {
Tim Peters6d6c1a32001-08-02 04:15:00 +000095 Py_INCREF(descr);
96 *pres = (PyObject *)descr;
97 return 1;
98 }
99 if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
100 PyErr_Format(PyExc_TypeError,
Barry Warsaw7ce36942001-08-24 18:34:26 +0000101 "descriptor '%s' for '%s' objects "
102 "doesn't apply to '%s' object",
Tim Peters6d6c1a32001-08-02 04:15:00 +0000103 descr_name((PyDescrObject *)descr),
104 descr->d_type->tp_name,
105 obj->ob_type->tp_name);
106 *pres = NULL;
107 return 1;
108 }
109 return 0;
110}
111
112static PyObject *
113method_get(PyMethodDescrObject *descr, PyObject *obj, PyTypeObject *type)
114{
115 PyObject *res;
116
117 if (descr_check((PyDescrObject *)descr, obj, type, &res))
118 return res;
119 return PyCFunction_New(descr->d_method, obj);
120}
121
122static PyObject *
123member_get(PyMemberDescrObject *descr, PyObject *obj, PyTypeObject *type)
124{
125 PyObject *res;
126
127 if (descr_check((PyDescrObject *)descr, obj, type, &res))
128 return res;
129 return PyMember_Get((char *)obj, descr->d_member,
130 descr->d_member->name);
131}
132
133static PyObject *
134getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
135{
136 PyObject *res;
137
138 if (descr_check((PyDescrObject *)descr, obj, type, &res))
139 return res;
140 if (descr->d_getset->get != NULL)
141 return descr->d_getset->get(obj, descr->d_getset->closure);
142 PyErr_Format(PyExc_TypeError,
143 "attribute '%300s' of '%.100s' objects is not readable",
144 descr_name((PyDescrObject *)descr),
145 descr->d_type->tp_name);
146 return NULL;
147}
148
149static PyObject *
150wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyTypeObject *type)
151{
152 PyObject *res;
153
154 if (descr_check((PyDescrObject *)descr, obj, type, &res))
155 return res;
156 return PyWrapper_New((PyObject *)descr, obj);
157}
158
159static int
160descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,
161 int *pres)
162{
163 assert(obj != NULL);
164 if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
165 PyErr_Format(PyExc_TypeError,
166 "descriptor '%.200s' for '%.100s' objects "
167 "doesn't apply to '%.100s' object",
168 descr_name(descr),
169 descr->d_type->tp_name,
170 obj->ob_type->tp_name);
171 *pres = -1;
172 return 1;
173 }
174 return 0;
175}
176
177static int
178member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)
179{
180 int res;
181
182 if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
183 return res;
184 return PyMember_Set((char *)obj, descr->d_member,
185 descr->d_member->name, value);
186}
187
188static int
189getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
190{
191 int res;
192
193 if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
194 return res;
195 if (descr->d_getset->set != NULL)
196 return descr->d_getset->set(obj, value,
197 descr->d_getset->closure);
198 PyErr_Format(PyExc_TypeError,
199 "attribute '%300s' of '%.100s' objects is not writable",
200 descr_name((PyDescrObject *)descr),
201 descr->d_type->tp_name);
202 return -1;
203}
204
205static PyObject *
206methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
207{
208 int argc;
209 PyObject *self, *func, *result;
210
211 /* Make sure that the first argument is acceptable as 'self' */
212 assert(PyTuple_Check(args));
213 argc = PyTuple_GET_SIZE(args);
214 if (argc < 1) {
215 PyErr_Format(PyExc_TypeError,
216 "descriptor '%.300s' of '%.100s' "
217 "object needs an argument",
218 descr_name((PyDescrObject *)descr),
219 descr->d_type->tp_name);
220 return NULL;
221 }
222 self = PyTuple_GET_ITEM(args, 0);
223 if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
224 PyErr_Format(PyExc_TypeError,
225 "descriptor '%.200s' "
226 "requires a '%.100s' object "
227 "but received a '%.100s'",
228 descr_name((PyDescrObject *)descr),
229 descr->d_type->tp_name,
230 self->ob_type->tp_name);
231 return NULL;
232 }
233
234 func = PyCFunction_New(descr->d_method, self);
235 if (func == NULL)
236 return NULL;
237 args = PyTuple_GetSlice(args, 1, argc);
238 if (args == NULL) {
239 Py_DECREF(func);
240 return NULL;
241 }
242 result = PyEval_CallObjectWithKeywords(func, args, kwds);
243 Py_DECREF(args);
244 Py_DECREF(func);
245 return result;
246}
247
248static PyObject *
249wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
250{
251 int argc;
252 PyObject *self, *func, *result;
253
254 /* Make sure that the first argument is acceptable as 'self' */
255 assert(PyTuple_Check(args));
256 argc = PyTuple_GET_SIZE(args);
257 if (argc < 1) {
258 PyErr_Format(PyExc_TypeError,
259 "descriptor '%.300s' of '%.100s' "
260 "object needs an argument",
261 descr_name((PyDescrObject *)descr),
262 descr->d_type->tp_name);
263 return NULL;
264 }
265 self = PyTuple_GET_ITEM(args, 0);
266 if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
267 PyErr_Format(PyExc_TypeError,
268 "descriptor '%.200s' "
269 "requires a '%.100s' object "
270 "but received a '%.100s'",
271 descr_name((PyDescrObject *)descr),
272 descr->d_type->tp_name,
273 self->ob_type->tp_name);
274 return NULL;
275 }
276
277 func = PyWrapper_New((PyObject *)descr, self);
278 if (func == NULL)
279 return NULL;
280 args = PyTuple_GetSlice(args, 1, argc);
281 if (args == NULL) {
282 Py_DECREF(func);
283 return NULL;
284 }
285 result = PyEval_CallObjectWithKeywords(func, args, kwds);
286 Py_DECREF(args);
287 Py_DECREF(func);
288 return result;
289}
290
291static PyObject *
292member_get_doc(PyMethodDescrObject *descr, void *closure)
293{
294 if (descr->d_method->ml_doc == NULL) {
295 Py_INCREF(Py_None);
296 return Py_None;
297 }
298 return PyString_FromString(descr->d_method->ml_doc);
299}
300
301static struct memberlist descr_members[] = {
302 {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},
303 {"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},
304 {0}
305};
306
307static struct getsetlist member_getset[] = {
308 {"__doc__", (getter)member_get_doc},
309 {0}
310};
311
312static PyObject *
313wrapper_get_doc(PyWrapperDescrObject *descr, void *closure)
314{
315 if (descr->d_base->doc == NULL) {
316 Py_INCREF(Py_None);
317 return Py_None;
318 }
319 return PyString_FromString(descr->d_base->doc);
320}
321
322static struct getsetlist wrapper_getset[] = {
323 {"__doc__", (getter)wrapper_get_doc},
324 {0}
325};
326
327static PyTypeObject PyMethodDescr_Type = {
328 PyObject_HEAD_INIT(&PyType_Type)
329 0,
330 "method_descriptor",
331 sizeof(PyMethodDescrObject),
332 0,
333 (destructor)descr_dealloc, /* tp_dealloc */
334 0, /* tp_print */
335 0, /* tp_getattr */
336 0, /* tp_setattr */
337 0, /* tp_compare */
338 (reprfunc)method_repr, /* tp_repr */
339 0, /* tp_as_number */
340 0, /* tp_as_sequence */
341 0, /* tp_as_mapping */
342 0, /* tp_hash */
343 (ternaryfunc)methoddescr_call, /* tp_call */
344 0, /* tp_str */
345 PyObject_GenericGetAttr, /* tp_getattro */
346 0, /* tp_setattro */
347 0, /* tp_as_buffer */
348 Py_TPFLAGS_DEFAULT, /* tp_flags */
349 0, /* tp_doc */
350 0, /* tp_traverse */
351 0, /* tp_clear */
352 0, /* tp_richcompare */
353 0, /* tp_weaklistoffset */
354 0, /* tp_iter */
355 0, /* tp_iternext */
356 0, /* tp_methods */
357 descr_members, /* tp_members */
358 member_getset, /* tp_getset */
359 0, /* tp_base */
360 0, /* tp_dict */
361 (descrgetfunc)method_get, /* tp_descr_get */
362 0, /* tp_descr_set */
363};
364
365static PyTypeObject PyMemberDescr_Type = {
366 PyObject_HEAD_INIT(&PyType_Type)
367 0,
368 "member_descriptor",
369 sizeof(PyMemberDescrObject),
370 0,
371 (destructor)descr_dealloc, /* tp_dealloc */
372 0, /* tp_print */
373 0, /* tp_getattr */
374 0, /* tp_setattr */
375 0, /* tp_compare */
376 (reprfunc)member_repr, /* tp_repr */
377 0, /* tp_as_number */
378 0, /* tp_as_sequence */
379 0, /* tp_as_mapping */
380 0, /* tp_hash */
381 (ternaryfunc)0, /* tp_call */
382 0, /* tp_str */
383 PyObject_GenericGetAttr, /* tp_getattro */
384 0, /* tp_setattro */
385 0, /* tp_as_buffer */
386 Py_TPFLAGS_DEFAULT, /* tp_flags */
387 0, /* tp_doc */
388 0, /* tp_traverse */
389 0, /* tp_clear */
390 0, /* tp_richcompare */
391 0, /* tp_weaklistoffset */
392 0, /* tp_iter */
393 0, /* tp_iternext */
394 0, /* tp_methods */
395 descr_members, /* tp_members */
396 0, /* tp_getset */
397 0, /* tp_base */
398 0, /* tp_dict */
399 (descrgetfunc)member_get, /* tp_descr_get */
400 (descrsetfunc)member_set, /* tp_descr_set */
401};
402
403static PyTypeObject PyGetSetDescr_Type = {
404 PyObject_HEAD_INIT(&PyType_Type)
405 0,
406 "getset_descriptor",
407 sizeof(PyGetSetDescrObject),
408 0,
409 (destructor)descr_dealloc, /* tp_dealloc */
410 0, /* tp_print */
411 0, /* tp_getattr */
412 0, /* tp_setattr */
413 0, /* tp_compare */
414 (reprfunc)getset_repr, /* tp_repr */
415 0, /* tp_as_number */
416 0, /* tp_as_sequence */
417 0, /* tp_as_mapping */
418 0, /* tp_hash */
419 (ternaryfunc)0, /* tp_call */
420 0, /* tp_str */
421 PyObject_GenericGetAttr, /* tp_getattro */
422 0, /* tp_setattro */
423 0, /* tp_as_buffer */
424 Py_TPFLAGS_DEFAULT, /* tp_flags */
425 0, /* tp_doc */
426 0, /* tp_traverse */
427 0, /* tp_clear */
428 0, /* tp_richcompare */
429 0, /* tp_weaklistoffset */
430 0, /* tp_iter */
431 0, /* tp_iternext */
432 0, /* tp_methods */
433 descr_members, /* tp_members */
434 0, /* tp_getset */
435 0, /* tp_base */
436 0, /* tp_dict */
437 (descrgetfunc)getset_get, /* tp_descr_get */
438 (descrsetfunc)getset_set, /* tp_descr_set */
439};
440
441static PyTypeObject PyWrapperDescr_Type = {
442 PyObject_HEAD_INIT(&PyType_Type)
443 0,
444 "wrapper_descriptor",
445 sizeof(PyWrapperDescrObject),
446 0,
447 (destructor)descr_dealloc, /* tp_dealloc */
448 0, /* tp_print */
449 0, /* tp_getattr */
450 0, /* tp_setattr */
451 0, /* tp_compare */
452 (reprfunc)wrapper_repr, /* tp_repr */
453 0, /* tp_as_number */
454 0, /* tp_as_sequence */
455 0, /* tp_as_mapping */
456 0, /* tp_hash */
457 (ternaryfunc)wrapperdescr_call, /* tp_call */
458 0, /* tp_str */
459 PyObject_GenericGetAttr, /* tp_getattro */
460 0, /* tp_setattro */
461 0, /* tp_as_buffer */
462 Py_TPFLAGS_DEFAULT, /* tp_flags */
463 0, /* tp_doc */
464 0, /* tp_traverse */
465 0, /* tp_clear */
466 0, /* tp_richcompare */
467 0, /* tp_weaklistoffset */
468 0, /* tp_iter */
469 0, /* tp_iternext */
470 0, /* tp_methods */
471 descr_members, /* tp_members */
472 wrapper_getset, /* tp_getset */
473 0, /* tp_base */
474 0, /* tp_dict */
475 (descrgetfunc)wrapper_get, /* tp_descr_get */
476 0, /* tp_descr_set */
477};
478
479static PyDescrObject *
480descr_new(PyTypeObject *descrtype, PyTypeObject *type, char *name)
481{
482 PyDescrObject *descr;
483
484 descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);
485 if (descr != NULL) {
486 Py_XINCREF(type);
487 descr->d_type = type;
488 descr->d_name = PyString_InternFromString(name);
489 if (descr->d_name == NULL) {
490 Py_DECREF(descr);
491 descr = NULL;
492 }
493 }
494 return descr;
495}
496
497PyObject *
498PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
499{
500 PyMethodDescrObject *descr;
501
502 descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
503 type, method->ml_name);
504 if (descr != NULL)
505 descr->d_method = method;
506 return (PyObject *)descr;
507}
508
509PyObject *
510PyDescr_NewMember(PyTypeObject *type, struct memberlist *member)
511{
512 PyMemberDescrObject *descr;
513
514 descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,
515 type, member->name);
516 if (descr != NULL)
517 descr->d_member = member;
518 return (PyObject *)descr;
519}
520
521PyObject *
522PyDescr_NewGetSet(PyTypeObject *type, struct getsetlist *getset)
523{
524 PyGetSetDescrObject *descr;
525
526 descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
527 type, getset->name);
528 if (descr != NULL)
529 descr->d_getset = getset;
530 return (PyObject *)descr;
531}
532
533PyObject *
534PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
535{
536 PyWrapperDescrObject *descr;
537
538 descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
539 type, base->name);
540 if (descr != NULL) {
541 descr->d_base = base;
542 descr->d_wrapped = wrapped;
543 }
544 return (PyObject *)descr;
545}
546
547int
548PyDescr_IsData(PyObject *d)
549{
550 return d->ob_type->tp_descr_set != NULL;
551}
552
553
554/* --- Readonly proxy for dictionaries (actually any mapping) --- */
555
556/* This has no reason to be in this file except that adding new files is a
557 bit of a pain */
558
559typedef struct {
560 PyObject_HEAD
561 PyObject *dict;
562} proxyobject;
563
564static int
565proxy_len(proxyobject *pp)
566{
567 return PyObject_Size(pp->dict);
568}
569
570static PyObject *
571proxy_getitem(proxyobject *pp, PyObject *key)
572{
573 return PyObject_GetItem(pp->dict, key);
574}
575
576static PyMappingMethods proxy_as_mapping = {
577 (inquiry)proxy_len, /* mp_length */
578 (binaryfunc)proxy_getitem, /* mp_subscript */
579 0, /* mp_ass_subscript */
580};
581
582static int
583proxy_contains(proxyobject *pp, PyObject *key)
584{
585 return PySequence_Contains(pp->dict, key);
586}
587
588static PySequenceMethods proxy_as_sequence = {
589 0, /* sq_length */
590 0, /* sq_concat */
591 0, /* sq_repeat */
592 0, /* sq_item */
593 0, /* sq_slice */
594 0, /* sq_ass_item */
595 0, /* sq_ass_slice */
596 (objobjproc)proxy_contains, /* sq_contains */
597 0, /* sq_inplace_concat */
598 0, /* sq_inplace_repeat */
599};
600
601static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000602proxy_has_key(proxyobject *pp, PyObject *key)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000603{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000604 return PyInt_FromLong(PySequence_Contains(pp->dict, key));
605}
606
607static PyObject *
608proxy_get(proxyobject *pp, PyObject *args)
609{
610 PyObject *key, *def = Py_None;
611
612 if (!PyArg_ParseTuple(args, "O|O:get", &key, &def))
613 return NULL;
614 return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
615}
616
617static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000618proxy_keys(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000619{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000620 return PyMapping_Keys(pp->dict);
621}
622
623static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000624proxy_values(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000625{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000626 return PyMapping_Values(pp->dict);
627}
628
629static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000630proxy_items(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000631{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000632 return PyMapping_Items(pp->dict);
633}
634
635static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000636proxy_copy(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000637{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000638 return PyObject_CallMethod(pp->dict, "copy", NULL);
639}
640
641static PyMethodDef proxy_methods[] = {
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000642 {"has_key", (PyCFunction)proxy_has_key, METH_O, "XXX"},
Tim Peters6d6c1a32001-08-02 04:15:00 +0000643 {"get", (PyCFunction)proxy_get, METH_VARARGS, "XXX"},
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000644 {"keys", (PyCFunction)proxy_keys, METH_NOARGS, "XXX"},
645 {"values", (PyCFunction)proxy_values, METH_NOARGS, "XXX"},
646 {"items", (PyCFunction)proxy_items, METH_NOARGS, "XXX"},
647 {"copy", (PyCFunction)proxy_copy, METH_NOARGS, "XXX"},
Tim Peters6d6c1a32001-08-02 04:15:00 +0000648 {0}
649};
650
651static void
652proxy_dealloc(proxyobject *pp)
653{
654 Py_DECREF(pp->dict);
655 PyObject_DEL(pp);
656}
657
658static PyObject *
659proxy_getiter(proxyobject *pp)
660{
661 return PyObject_GetIter(pp->dict);
662}
663
664PyObject *
665proxy_str(proxyobject *pp)
666{
667 return PyObject_Str(pp->dict);
668}
669
670PyTypeObject proxytype = {
671 PyObject_HEAD_INIT(&PyType_Type)
672 0, /* ob_size */
673 "dict-proxy", /* tp_name */
674 sizeof(proxyobject), /* tp_basicsize */
675 0, /* tp_itemsize */
676 /* methods */
677 (destructor)proxy_dealloc, /* tp_dealloc */
678 0, /* tp_print */
679 0, /* tp_getattr */
680 0, /* tp_setattr */
681 0, /* tp_compare */
682 0, /* tp_repr */
683 0, /* tp_as_number */
684 &proxy_as_sequence, /* tp_as_sequence */
685 &proxy_as_mapping, /* tp_as_mapping */
686 0, /* tp_hash */
687 0, /* tp_call */
688 (reprfunc)proxy_str, /* tp_str */
689 PyObject_GenericGetAttr, /* tp_getattro */
690 0, /* tp_setattro */
691 0, /* tp_as_buffer */
692 Py_TPFLAGS_DEFAULT, /* tp_flags */
693 0, /* tp_doc */
694 0, /* tp_traverse */
695 0, /* tp_clear */
696 0, /* tp_richcompare */
697 0, /* tp_weaklistoffset */
698 (getiterfunc)proxy_getiter, /* tp_iter */
699 0, /* tp_iternext */
700 proxy_methods, /* tp_methods */
701 0, /* tp_members */
702 0, /* tp_getset */
703 0, /* tp_base */
704 0, /* tp_dict */
705 0, /* tp_descr_get */
706 0, /* tp_descr_set */
707};
708
709PyObject *
710PyDictProxy_New(PyObject *dict)
711{
712 proxyobject *pp;
713
714 pp = PyObject_NEW(proxyobject, &proxytype);
715 if (pp != NULL) {
716 Py_INCREF(dict);
717 pp->dict = dict;
718 }
719 return (PyObject *)pp;
720}
721
722
723/* --- Wrapper object for "slot" methods --- */
724
725/* This has no reason to be in this file except that adding new files is a
726 bit of a pain */
727
728typedef struct {
729 PyObject_HEAD
730 PyWrapperDescrObject *descr;
731 PyObject *self;
732} wrapperobject;
733
734static void
735wrapper_dealloc(wrapperobject *wp)
736{
737 Py_XDECREF(wp->descr);
738 Py_XDECREF(wp->self);
739 PyObject_DEL(wp);
740}
741
742static PyMethodDef wrapper_methods[] = {
743 {0}
744};
745
746static PyObject *
747wrapper_name(wrapperobject *wp)
748{
749 char *s = wp->descr->d_base->name;
750
751 return PyString_FromString(s);
752}
753
754static PyObject *
755wrapper_doc(wrapperobject *wp)
756{
757 char *s = wp->descr->d_base->doc;
758
759 if (s == NULL) {
760 Py_INCREF(Py_None);
761 return Py_None;
762 }
763 else {
764 return PyString_FromString(s);
765 }
766}
767
768static struct getsetlist wrapper_getsets[] = {
769 {"__name__", (getter)wrapper_name},
770 {"__doc__", (getter)wrapper_doc},
771 {0}
772};
773
774static PyObject *
775wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
776{
777 wrapperfunc wrapper = wp->descr->d_base->wrapper;
778 PyObject *self = wp->self;
779
780 return (*wrapper)(self, args, wp->descr->d_wrapped);
781}
782
783PyTypeObject wrappertype = {
784 PyObject_HEAD_INIT(&PyType_Type)
785 0, /* ob_size */
786 "method-wrapper", /* tp_name */
787 sizeof(wrapperobject), /* tp_basicsize */
788 0, /* tp_itemsize */
789 /* methods */
790 (destructor)wrapper_dealloc, /* tp_dealloc */
791 0, /* tp_print */
792 0, /* tp_getattr */
793 0, /* tp_setattr */
794 0, /* tp_compare */
795 0, /* tp_repr */
796 0, /* tp_as_number */
797 0, /* tp_as_sequence */
798 0, /* tp_as_mapping */
799 0, /* tp_hash */
800 (ternaryfunc)wrapper_call, /* tp_call */
801 0, /* tp_str */
802 PyObject_GenericGetAttr, /* tp_getattro */
803 0, /* tp_setattro */
804 0, /* tp_as_buffer */
805 Py_TPFLAGS_DEFAULT, /* tp_flags */
806 0, /* tp_doc */
807 0, /* tp_traverse */
808 0, /* tp_clear */
809 0, /* tp_richcompare */
810 0, /* tp_weaklistoffset */
811 0, /* tp_iter */
812 0, /* tp_iternext */
813 wrapper_methods, /* tp_methods */
814 0, /* tp_members */
815 wrapper_getsets, /* tp_getset */
816 0, /* tp_base */
817 0, /* tp_dict */
818 0, /* tp_descr_get */
819 0, /* tp_descr_set */
820};
821
822PyObject *
823PyWrapper_New(PyObject *d, PyObject *self)
824{
825 wrapperobject *wp;
826 PyWrapperDescrObject *descr;
827
828 assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));
829 descr = (PyWrapperDescrObject *)d;
830 assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type)));
831
832 wp = PyObject_NEW(wrapperobject, &wrappertype);
833 if (wp != NULL) {
834 Py_INCREF(descr);
835 wp->descr = descr;
836 Py_INCREF(self);
837 wp->self = self;
838 }
839 return (PyObject *)wp;
840}
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000841
842
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000843/* A built-in 'property' type */
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000844
845/*
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000846 class property(object):
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000847
848 def __init__(self, get=None, set=None):
849 self.__get = get
850 self.__set = set
851
852 def __get__(self, inst, type=None):
853 if self.__get is None:
854 raise AttributeError, "unreadable attribute"
855 if inst is None:
856 return self
857 return self.__get(inst)
858
859 def __set__(self, inst, value):
860 if self.__set is None:
861 raise AttributeError, "unsettable attribute"
862 return self.__set(inst, value)
863*/
864
865typedef struct {
866 PyObject_HEAD
867 PyObject *get;
868 PyObject *set;
Guido van Rossum271410a2001-08-24 15:23:20 +0000869 PyObject *del;
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000870} propertyobject;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000871
872static void
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000873property_dealloc(PyObject *self)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000874{
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000875 propertyobject *gs = (propertyobject *)self;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000876
877 Py_XDECREF(gs->get);
878 Py_XDECREF(gs->set);
Guido van Rossum271410a2001-08-24 15:23:20 +0000879 Py_XDECREF(gs->del);
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000880 self->ob_type->tp_free(self);
881}
882
883static PyObject *
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000884property_descr_get(PyObject *self, PyObject *obj, PyObject *type)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000885{
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000886 propertyobject *gs = (propertyobject *)self;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000887
888 if (gs->get == NULL) {
889 PyErr_SetString(PyExc_AttributeError, "unreadable attribute");
890 return NULL;
891 }
892 if (obj == NULL || obj == Py_None) {
893 Py_INCREF(self);
894 return self;
895 }
896 return PyObject_CallFunction(gs->get, "(O)", obj);
897}
898
899static int
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000900property_descr_set(PyObject *self, PyObject *obj, PyObject *value)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000901{
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000902 propertyobject *gs = (propertyobject *)self;
Guido van Rossum271410a2001-08-24 15:23:20 +0000903 PyObject *func, *res;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000904
Guido van Rossum271410a2001-08-24 15:23:20 +0000905 if (value == NULL)
906 func = gs->del;
907 else
908 func = gs->set;
909 if (func == NULL) {
910 PyErr_SetString(PyExc_AttributeError,
911 value == NULL ?
912 "can't delete attribute" :
913 "can't set attribute");
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000914 return -1;
915 }
Guido van Rossum845fc482001-08-24 10:17:36 +0000916 if (value == NULL)
Guido van Rossum271410a2001-08-24 15:23:20 +0000917 res = PyObject_CallFunction(func, "(O)", obj);
Guido van Rossum845fc482001-08-24 10:17:36 +0000918 else
Guido van Rossum271410a2001-08-24 15:23:20 +0000919 res = PyObject_CallFunction(func, "(OO)", obj, value);
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000920 if (res == NULL)
921 return -1;
922 Py_DECREF(res);
923 return 0;
924}
925
926static int
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000927property_init(PyObject *self, PyObject *args, PyObject *kwds)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000928{
Guido van Rossum271410a2001-08-24 15:23:20 +0000929 PyObject *get = NULL, *set = NULL, *del = NULL;
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000930 propertyobject *gs = (propertyobject *)self;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000931
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000932 if (!PyArg_ParseTuple(args, "|OOO:property", &get, &set, &del))
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000933 return -1;
934 if (get == Py_None)
935 get = NULL;
936 if (set == Py_None)
937 set = NULL;
938 Py_XINCREF(get);
939 Py_XINCREF(set);
Guido van Rossum271410a2001-08-24 15:23:20 +0000940 Py_XINCREF(del);
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000941 gs->get = get;
942 gs->set = set;
Guido van Rossum271410a2001-08-24 15:23:20 +0000943 gs->del = del;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000944 return 0;
945}
946
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000947static char property_doc[] =
948"property([getfunc[, setfunc[, delfunc]]]) -> property attribute\n"
Guido van Rossum91c0d8a2001-08-24 09:55:51 +0000949"Typical use to define a managed attribute x of C instances:\n"
950"class C(object):\n"
951" def getx(self): return self.__x\n"
952" def setx(self, value): self.__x = value\n"
Guido van Rossum271410a2001-08-24 15:23:20 +0000953" def delx(self): del self.__x\n"
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000954" x = property(getx, setx, delx)";
Guido van Rossum91c0d8a2001-08-24 09:55:51 +0000955
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000956PyTypeObject PyProperty_Type = {
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000957 PyObject_HEAD_INIT(&PyType_Type)
958 0, /* ob_size */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000959 "property", /* tp_name */
960 sizeof(propertyobject), /* tp_basicsize */
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000961 0, /* tp_itemsize */
962 /* methods */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000963 property_dealloc, /* tp_dealloc */
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000964 0, /* tp_print */
965 0, /* tp_getattr */
966 0, /* tp_setattr */
967 0, /* tp_compare */
968 0, /* tp_repr */
969 0, /* tp_as_number */
970 0, /* tp_as_sequence */
971 0, /* tp_as_mapping */
972 0, /* tp_hash */
973 0, /* tp_call */
974 0, /* tp_str */
975 PyObject_GenericGetAttr, /* tp_getattro */
976 0, /* tp_setattro */
977 0, /* tp_as_buffer */
Guido van Rossum147b13c2001-08-30 03:10:36 +0000978 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000979 property_doc, /* tp_doc */
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000980 0, /* tp_traverse */
981 0, /* tp_clear */
982 0, /* tp_richcompare */
983 0, /* tp_weaklistoffset */
984 0, /* tp_iter */
985 0, /* tp_iternext */
986 0, /* tp_methods */
987 0, /* tp_members */
988 0, /* tp_getset */
989 0, /* tp_base */
990 0, /* tp_dict */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000991 property_descr_get, /* tp_descr_get */
992 property_descr_set, /* tp_descr_set */
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000993 0, /* tp_dictoffset */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000994 property_init, /* tp_init */
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000995 PyType_GenericAlloc, /* tp_alloc */
996 PyType_GenericNew, /* tp_new */
997 _PyObject_Del, /* tp_free */
998};