blob: fea67f3f9f60aac799b50b7a969301c081fd1994 [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;
Guido van Rossum6f799372001-09-20 20:46:19 +000024 PyMemberDef *d_member;
Tim Peters6d6c1a32001-08-02 04:15:00 +000025} PyMemberDescrObject;
26
27typedef struct {
28 COMMON;
Guido van Rossum32d34c82001-09-20 21:45:26 +000029 PyGetSetDef *d_getset;
Tim Peters6d6c1a32001-08-02 04:15:00 +000030} 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;
Guido van Rossum6f799372001-09-20 20:46:19 +0000129 return PyMember_GetOne((char *)obj, descr->d_member);
Tim Peters6d6c1a32001-08-02 04:15:00 +0000130}
131
132static PyObject *
133getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
134{
135 PyObject *res;
136
137 if (descr_check((PyDescrObject *)descr, obj, type, &res))
138 return res;
139 if (descr->d_getset->get != NULL)
140 return descr->d_getset->get(obj, descr->d_getset->closure);
141 PyErr_Format(PyExc_TypeError,
142 "attribute '%300s' of '%.100s' objects is not readable",
143 descr_name((PyDescrObject *)descr),
144 descr->d_type->tp_name);
145 return NULL;
146}
147
148static PyObject *
149wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyTypeObject *type)
150{
151 PyObject *res;
152
153 if (descr_check((PyDescrObject *)descr, obj, type, &res))
154 return res;
155 return PyWrapper_New((PyObject *)descr, obj);
156}
157
158static int
159descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,
160 int *pres)
161{
162 assert(obj != NULL);
163 if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
164 PyErr_Format(PyExc_TypeError,
165 "descriptor '%.200s' for '%.100s' objects "
166 "doesn't apply to '%.100s' object",
167 descr_name(descr),
168 descr->d_type->tp_name,
169 obj->ob_type->tp_name);
170 *pres = -1;
171 return 1;
172 }
173 return 0;
174}
175
176static int
177member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)
178{
179 int res;
180
181 if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
182 return res;
Guido van Rossum6f799372001-09-20 20:46:19 +0000183 return PyMember_SetOne((char *)obj, descr->d_member, value);
Tim Peters6d6c1a32001-08-02 04:15:00 +0000184}
185
186static int
187getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
188{
189 int res;
190
191 if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
192 return res;
193 if (descr->d_getset->set != NULL)
194 return descr->d_getset->set(obj, value,
195 descr->d_getset->closure);
196 PyErr_Format(PyExc_TypeError,
197 "attribute '%300s' of '%.100s' objects is not writable",
198 descr_name((PyDescrObject *)descr),
199 descr->d_type->tp_name);
200 return -1;
201}
202
203static PyObject *
204methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
205{
206 int argc;
207 PyObject *self, *func, *result;
208
209 /* Make sure that the first argument is acceptable as 'self' */
210 assert(PyTuple_Check(args));
211 argc = PyTuple_GET_SIZE(args);
212 if (argc < 1) {
213 PyErr_Format(PyExc_TypeError,
214 "descriptor '%.300s' of '%.100s' "
215 "object needs an argument",
216 descr_name((PyDescrObject *)descr),
217 descr->d_type->tp_name);
218 return NULL;
219 }
220 self = PyTuple_GET_ITEM(args, 0);
221 if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
222 PyErr_Format(PyExc_TypeError,
223 "descriptor '%.200s' "
224 "requires a '%.100s' object "
225 "but received a '%.100s'",
226 descr_name((PyDescrObject *)descr),
227 descr->d_type->tp_name,
228 self->ob_type->tp_name);
229 return NULL;
230 }
231
232 func = PyCFunction_New(descr->d_method, self);
233 if (func == NULL)
234 return NULL;
235 args = PyTuple_GetSlice(args, 1, argc);
236 if (args == NULL) {
237 Py_DECREF(func);
238 return NULL;
239 }
240 result = PyEval_CallObjectWithKeywords(func, args, kwds);
241 Py_DECREF(args);
242 Py_DECREF(func);
243 return result;
244}
245
246static PyObject *
247wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
248{
249 int argc;
250 PyObject *self, *func, *result;
251
252 /* Make sure that the first argument is acceptable as 'self' */
253 assert(PyTuple_Check(args));
254 argc = PyTuple_GET_SIZE(args);
255 if (argc < 1) {
256 PyErr_Format(PyExc_TypeError,
257 "descriptor '%.300s' of '%.100s' "
258 "object needs an argument",
259 descr_name((PyDescrObject *)descr),
260 descr->d_type->tp_name);
261 return NULL;
262 }
263 self = PyTuple_GET_ITEM(args, 0);
264 if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
265 PyErr_Format(PyExc_TypeError,
266 "descriptor '%.200s' "
267 "requires a '%.100s' object "
268 "but received a '%.100s'",
269 descr_name((PyDescrObject *)descr),
270 descr->d_type->tp_name,
271 self->ob_type->tp_name);
272 return NULL;
273 }
274
275 func = PyWrapper_New((PyObject *)descr, self);
276 if (func == NULL)
277 return NULL;
278 args = PyTuple_GetSlice(args, 1, argc);
279 if (args == NULL) {
280 Py_DECREF(func);
281 return NULL;
282 }
283 result = PyEval_CallObjectWithKeywords(func, args, kwds);
284 Py_DECREF(args);
285 Py_DECREF(func);
286 return result;
287}
288
289static PyObject *
Guido van Rossum6f799372001-09-20 20:46:19 +0000290method_get_doc(PyMethodDescrObject *descr, void *closure)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000291{
292 if (descr->d_method->ml_doc == NULL) {
293 Py_INCREF(Py_None);
294 return Py_None;
295 }
296 return PyString_FromString(descr->d_method->ml_doc);
297}
298
Guido van Rossum6f799372001-09-20 20:46:19 +0000299static PyMemberDef descr_members[] = {
Tim Peters6d6c1a32001-08-02 04:15:00 +0000300 {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},
301 {"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},
302 {0}
303};
304
Guido van Rossum32d34c82001-09-20 21:45:26 +0000305static PyGetSetDef method_getset[] = {
Guido van Rossum6f799372001-09-20 20:46:19 +0000306 {"__doc__", (getter)method_get_doc},
307 {0}
308};
309
310static PyObject *
311member_get_doc(PyMemberDescrObject *descr, void *closure)
312{
313 if (descr->d_member->doc == NULL) {
314 Py_INCREF(Py_None);
315 return Py_None;
316 }
317 return PyString_FromString(descr->d_member->doc);
318}
319
Guido van Rossum32d34c82001-09-20 21:45:26 +0000320static PyGetSetDef member_getset[] = {
Tim Peters6d6c1a32001-08-02 04:15:00 +0000321 {"__doc__", (getter)member_get_doc},
322 {0}
323};
324
325static PyObject *
Guido van Rossum32d34c82001-09-20 21:45:26 +0000326getset_get_doc(PyGetSetDescrObject *descr, void *closure)
327{
328 if (descr->d_getset->doc == NULL) {
329 Py_INCREF(Py_None);
330 return Py_None;
331 }
332 return PyString_FromString(descr->d_getset->doc);
333}
334
335static PyGetSetDef getset_getset[] = {
336 {"__doc__", (getter)getset_get_doc},
337 {0}
338};
339
340static PyObject *
Tim Peters6d6c1a32001-08-02 04:15:00 +0000341wrapper_get_doc(PyWrapperDescrObject *descr, void *closure)
342{
343 if (descr->d_base->doc == NULL) {
344 Py_INCREF(Py_None);
345 return Py_None;
346 }
347 return PyString_FromString(descr->d_base->doc);
348}
349
Guido van Rossum32d34c82001-09-20 21:45:26 +0000350static PyGetSetDef wrapper_getset[] = {
Tim Peters6d6c1a32001-08-02 04:15:00 +0000351 {"__doc__", (getter)wrapper_get_doc},
352 {0}
353};
354
355static PyTypeObject PyMethodDescr_Type = {
356 PyObject_HEAD_INIT(&PyType_Type)
357 0,
358 "method_descriptor",
359 sizeof(PyMethodDescrObject),
360 0,
361 (destructor)descr_dealloc, /* tp_dealloc */
362 0, /* tp_print */
363 0, /* tp_getattr */
364 0, /* tp_setattr */
365 0, /* tp_compare */
366 (reprfunc)method_repr, /* tp_repr */
367 0, /* tp_as_number */
368 0, /* tp_as_sequence */
369 0, /* tp_as_mapping */
370 0, /* tp_hash */
371 (ternaryfunc)methoddescr_call, /* tp_call */
372 0, /* tp_str */
373 PyObject_GenericGetAttr, /* tp_getattro */
374 0, /* tp_setattro */
375 0, /* tp_as_buffer */
376 Py_TPFLAGS_DEFAULT, /* tp_flags */
377 0, /* tp_doc */
378 0, /* tp_traverse */
379 0, /* tp_clear */
380 0, /* tp_richcompare */
381 0, /* tp_weaklistoffset */
382 0, /* tp_iter */
383 0, /* tp_iternext */
384 0, /* tp_methods */
385 descr_members, /* tp_members */
Guido van Rossum6f799372001-09-20 20:46:19 +0000386 method_getset, /* tp_getset */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000387 0, /* tp_base */
388 0, /* tp_dict */
389 (descrgetfunc)method_get, /* tp_descr_get */
390 0, /* tp_descr_set */
391};
392
393static PyTypeObject PyMemberDescr_Type = {
394 PyObject_HEAD_INIT(&PyType_Type)
395 0,
396 "member_descriptor",
397 sizeof(PyMemberDescrObject),
398 0,
399 (destructor)descr_dealloc, /* tp_dealloc */
400 0, /* tp_print */
401 0, /* tp_getattr */
402 0, /* tp_setattr */
403 0, /* tp_compare */
404 (reprfunc)member_repr, /* tp_repr */
405 0, /* tp_as_number */
406 0, /* tp_as_sequence */
407 0, /* tp_as_mapping */
408 0, /* tp_hash */
409 (ternaryfunc)0, /* tp_call */
410 0, /* tp_str */
411 PyObject_GenericGetAttr, /* tp_getattro */
412 0, /* tp_setattro */
413 0, /* tp_as_buffer */
414 Py_TPFLAGS_DEFAULT, /* tp_flags */
415 0, /* tp_doc */
416 0, /* tp_traverse */
417 0, /* tp_clear */
418 0, /* tp_richcompare */
419 0, /* tp_weaklistoffset */
420 0, /* tp_iter */
421 0, /* tp_iternext */
422 0, /* tp_methods */
423 descr_members, /* tp_members */
Guido van Rossum6f799372001-09-20 20:46:19 +0000424 member_getset, /* tp_getset */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000425 0, /* tp_base */
426 0, /* tp_dict */
427 (descrgetfunc)member_get, /* tp_descr_get */
428 (descrsetfunc)member_set, /* tp_descr_set */
429};
430
431static PyTypeObject PyGetSetDescr_Type = {
432 PyObject_HEAD_INIT(&PyType_Type)
433 0,
434 "getset_descriptor",
435 sizeof(PyGetSetDescrObject),
436 0,
437 (destructor)descr_dealloc, /* tp_dealloc */
438 0, /* tp_print */
439 0, /* tp_getattr */
440 0, /* tp_setattr */
441 0, /* tp_compare */
442 (reprfunc)getset_repr, /* tp_repr */
443 0, /* tp_as_number */
444 0, /* tp_as_sequence */
445 0, /* tp_as_mapping */
446 0, /* tp_hash */
447 (ternaryfunc)0, /* tp_call */
448 0, /* tp_str */
449 PyObject_GenericGetAttr, /* tp_getattro */
450 0, /* tp_setattro */
451 0, /* tp_as_buffer */
452 Py_TPFLAGS_DEFAULT, /* tp_flags */
453 0, /* tp_doc */
454 0, /* tp_traverse */
455 0, /* tp_clear */
456 0, /* tp_richcompare */
457 0, /* tp_weaklistoffset */
458 0, /* tp_iter */
459 0, /* tp_iternext */
460 0, /* tp_methods */
461 descr_members, /* tp_members */
Guido van Rossum32d34c82001-09-20 21:45:26 +0000462 getset_getset, /* tp_getset */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000463 0, /* tp_base */
464 0, /* tp_dict */
465 (descrgetfunc)getset_get, /* tp_descr_get */
466 (descrsetfunc)getset_set, /* tp_descr_set */
467};
468
469static PyTypeObject PyWrapperDescr_Type = {
470 PyObject_HEAD_INIT(&PyType_Type)
471 0,
472 "wrapper_descriptor",
473 sizeof(PyWrapperDescrObject),
474 0,
475 (destructor)descr_dealloc, /* tp_dealloc */
476 0, /* tp_print */
477 0, /* tp_getattr */
478 0, /* tp_setattr */
479 0, /* tp_compare */
480 (reprfunc)wrapper_repr, /* tp_repr */
481 0, /* tp_as_number */
482 0, /* tp_as_sequence */
483 0, /* tp_as_mapping */
484 0, /* tp_hash */
485 (ternaryfunc)wrapperdescr_call, /* tp_call */
486 0, /* tp_str */
487 PyObject_GenericGetAttr, /* tp_getattro */
488 0, /* tp_setattro */
489 0, /* tp_as_buffer */
490 Py_TPFLAGS_DEFAULT, /* tp_flags */
491 0, /* tp_doc */
492 0, /* tp_traverse */
493 0, /* tp_clear */
494 0, /* tp_richcompare */
495 0, /* tp_weaklistoffset */
496 0, /* tp_iter */
497 0, /* tp_iternext */
498 0, /* tp_methods */
499 descr_members, /* tp_members */
500 wrapper_getset, /* tp_getset */
501 0, /* tp_base */
502 0, /* tp_dict */
503 (descrgetfunc)wrapper_get, /* tp_descr_get */
504 0, /* tp_descr_set */
505};
506
507static PyDescrObject *
508descr_new(PyTypeObject *descrtype, PyTypeObject *type, char *name)
509{
510 PyDescrObject *descr;
511
512 descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);
513 if (descr != NULL) {
514 Py_XINCREF(type);
515 descr->d_type = type;
516 descr->d_name = PyString_InternFromString(name);
517 if (descr->d_name == NULL) {
518 Py_DECREF(descr);
519 descr = NULL;
520 }
521 }
522 return descr;
523}
524
525PyObject *
526PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
527{
528 PyMethodDescrObject *descr;
529
530 descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
531 type, method->ml_name);
532 if (descr != NULL)
533 descr->d_method = method;
534 return (PyObject *)descr;
535}
536
537PyObject *
Guido van Rossum6f799372001-09-20 20:46:19 +0000538PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000539{
540 PyMemberDescrObject *descr;
541
542 descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,
543 type, member->name);
544 if (descr != NULL)
545 descr->d_member = member;
546 return (PyObject *)descr;
547}
548
549PyObject *
Guido van Rossum32d34c82001-09-20 21:45:26 +0000550PyDescr_NewGetSet(PyTypeObject *type, PyGetSetDef *getset)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000551{
552 PyGetSetDescrObject *descr;
553
554 descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
555 type, getset->name);
556 if (descr != NULL)
557 descr->d_getset = getset;
558 return (PyObject *)descr;
559}
560
561PyObject *
562PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
563{
564 PyWrapperDescrObject *descr;
565
566 descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
567 type, base->name);
568 if (descr != NULL) {
569 descr->d_base = base;
570 descr->d_wrapped = wrapped;
571 }
572 return (PyObject *)descr;
573}
574
575int
576PyDescr_IsData(PyObject *d)
577{
578 return d->ob_type->tp_descr_set != NULL;
579}
580
581
582/* --- Readonly proxy for dictionaries (actually any mapping) --- */
583
584/* This has no reason to be in this file except that adding new files is a
585 bit of a pain */
586
587typedef struct {
588 PyObject_HEAD
589 PyObject *dict;
590} proxyobject;
591
592static int
593proxy_len(proxyobject *pp)
594{
595 return PyObject_Size(pp->dict);
596}
597
598static PyObject *
599proxy_getitem(proxyobject *pp, PyObject *key)
600{
601 return PyObject_GetItem(pp->dict, key);
602}
603
604static PyMappingMethods proxy_as_mapping = {
605 (inquiry)proxy_len, /* mp_length */
606 (binaryfunc)proxy_getitem, /* mp_subscript */
607 0, /* mp_ass_subscript */
608};
609
610static int
611proxy_contains(proxyobject *pp, PyObject *key)
612{
613 return PySequence_Contains(pp->dict, key);
614}
615
616static PySequenceMethods proxy_as_sequence = {
617 0, /* sq_length */
618 0, /* sq_concat */
619 0, /* sq_repeat */
620 0, /* sq_item */
621 0, /* sq_slice */
622 0, /* sq_ass_item */
623 0, /* sq_ass_slice */
624 (objobjproc)proxy_contains, /* sq_contains */
625 0, /* sq_inplace_concat */
626 0, /* sq_inplace_repeat */
627};
628
629static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000630proxy_has_key(proxyobject *pp, PyObject *key)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000631{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000632 return PyInt_FromLong(PySequence_Contains(pp->dict, key));
633}
634
635static PyObject *
636proxy_get(proxyobject *pp, PyObject *args)
637{
638 PyObject *key, *def = Py_None;
639
640 if (!PyArg_ParseTuple(args, "O|O:get", &key, &def))
641 return NULL;
642 return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
643}
644
645static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000646proxy_keys(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000647{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000648 return PyMapping_Keys(pp->dict);
649}
650
651static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000652proxy_values(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000653{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000654 return PyMapping_Values(pp->dict);
655}
656
657static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000658proxy_items(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000659{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000660 return PyMapping_Items(pp->dict);
661}
662
663static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000664proxy_copy(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000665{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000666 return PyObject_CallMethod(pp->dict, "copy", NULL);
667}
668
669static PyMethodDef proxy_methods[] = {
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000670 {"has_key", (PyCFunction)proxy_has_key, METH_O, "XXX"},
Tim Peters6d6c1a32001-08-02 04:15:00 +0000671 {"get", (PyCFunction)proxy_get, METH_VARARGS, "XXX"},
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000672 {"keys", (PyCFunction)proxy_keys, METH_NOARGS, "XXX"},
673 {"values", (PyCFunction)proxy_values, METH_NOARGS, "XXX"},
674 {"items", (PyCFunction)proxy_items, METH_NOARGS, "XXX"},
675 {"copy", (PyCFunction)proxy_copy, METH_NOARGS, "XXX"},
Tim Peters6d6c1a32001-08-02 04:15:00 +0000676 {0}
677};
678
679static void
680proxy_dealloc(proxyobject *pp)
681{
682 Py_DECREF(pp->dict);
683 PyObject_DEL(pp);
684}
685
686static PyObject *
687proxy_getiter(proxyobject *pp)
688{
689 return PyObject_GetIter(pp->dict);
690}
691
692PyObject *
693proxy_str(proxyobject *pp)
694{
695 return PyObject_Str(pp->dict);
696}
697
698PyTypeObject proxytype = {
699 PyObject_HEAD_INIT(&PyType_Type)
700 0, /* ob_size */
701 "dict-proxy", /* tp_name */
702 sizeof(proxyobject), /* tp_basicsize */
703 0, /* tp_itemsize */
704 /* methods */
705 (destructor)proxy_dealloc, /* tp_dealloc */
706 0, /* tp_print */
707 0, /* tp_getattr */
708 0, /* tp_setattr */
709 0, /* tp_compare */
710 0, /* tp_repr */
711 0, /* tp_as_number */
712 &proxy_as_sequence, /* tp_as_sequence */
713 &proxy_as_mapping, /* tp_as_mapping */
714 0, /* tp_hash */
715 0, /* tp_call */
716 (reprfunc)proxy_str, /* tp_str */
717 PyObject_GenericGetAttr, /* tp_getattro */
718 0, /* tp_setattro */
719 0, /* tp_as_buffer */
720 Py_TPFLAGS_DEFAULT, /* tp_flags */
721 0, /* tp_doc */
722 0, /* tp_traverse */
723 0, /* tp_clear */
724 0, /* tp_richcompare */
725 0, /* tp_weaklistoffset */
726 (getiterfunc)proxy_getiter, /* tp_iter */
727 0, /* tp_iternext */
728 proxy_methods, /* tp_methods */
729 0, /* tp_members */
730 0, /* tp_getset */
731 0, /* tp_base */
732 0, /* tp_dict */
733 0, /* tp_descr_get */
734 0, /* tp_descr_set */
735};
736
737PyObject *
738PyDictProxy_New(PyObject *dict)
739{
740 proxyobject *pp;
741
742 pp = PyObject_NEW(proxyobject, &proxytype);
743 if (pp != NULL) {
744 Py_INCREF(dict);
745 pp->dict = dict;
746 }
747 return (PyObject *)pp;
748}
749
750
751/* --- Wrapper object for "slot" methods --- */
752
753/* This has no reason to be in this file except that adding new files is a
754 bit of a pain */
755
756typedef struct {
757 PyObject_HEAD
758 PyWrapperDescrObject *descr;
759 PyObject *self;
760} wrapperobject;
761
762static void
763wrapper_dealloc(wrapperobject *wp)
764{
765 Py_XDECREF(wp->descr);
766 Py_XDECREF(wp->self);
767 PyObject_DEL(wp);
768}
769
770static PyMethodDef wrapper_methods[] = {
771 {0}
772};
773
774static PyObject *
775wrapper_name(wrapperobject *wp)
776{
777 char *s = wp->descr->d_base->name;
778
779 return PyString_FromString(s);
780}
781
782static PyObject *
783wrapper_doc(wrapperobject *wp)
784{
785 char *s = wp->descr->d_base->doc;
786
787 if (s == NULL) {
788 Py_INCREF(Py_None);
789 return Py_None;
790 }
791 else {
792 return PyString_FromString(s);
793 }
794}
795
Guido van Rossum32d34c82001-09-20 21:45:26 +0000796static PyGetSetDef wrapper_getsets[] = {
Tim Peters6d6c1a32001-08-02 04:15:00 +0000797 {"__name__", (getter)wrapper_name},
798 {"__doc__", (getter)wrapper_doc},
799 {0}
800};
801
802static PyObject *
803wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
804{
805 wrapperfunc wrapper = wp->descr->d_base->wrapper;
806 PyObject *self = wp->self;
807
808 return (*wrapper)(self, args, wp->descr->d_wrapped);
809}
810
811PyTypeObject wrappertype = {
812 PyObject_HEAD_INIT(&PyType_Type)
813 0, /* ob_size */
814 "method-wrapper", /* tp_name */
815 sizeof(wrapperobject), /* tp_basicsize */
816 0, /* tp_itemsize */
817 /* methods */
818 (destructor)wrapper_dealloc, /* tp_dealloc */
819 0, /* tp_print */
820 0, /* tp_getattr */
821 0, /* tp_setattr */
822 0, /* tp_compare */
823 0, /* tp_repr */
824 0, /* tp_as_number */
825 0, /* tp_as_sequence */
826 0, /* tp_as_mapping */
827 0, /* tp_hash */
828 (ternaryfunc)wrapper_call, /* tp_call */
829 0, /* tp_str */
830 PyObject_GenericGetAttr, /* tp_getattro */
831 0, /* tp_setattro */
832 0, /* tp_as_buffer */
833 Py_TPFLAGS_DEFAULT, /* tp_flags */
834 0, /* tp_doc */
835 0, /* tp_traverse */
836 0, /* tp_clear */
837 0, /* tp_richcompare */
838 0, /* tp_weaklistoffset */
839 0, /* tp_iter */
840 0, /* tp_iternext */
841 wrapper_methods, /* tp_methods */
842 0, /* tp_members */
843 wrapper_getsets, /* tp_getset */
844 0, /* tp_base */
845 0, /* tp_dict */
846 0, /* tp_descr_get */
847 0, /* tp_descr_set */
848};
849
850PyObject *
851PyWrapper_New(PyObject *d, PyObject *self)
852{
853 wrapperobject *wp;
854 PyWrapperDescrObject *descr;
855
856 assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));
857 descr = (PyWrapperDescrObject *)d;
858 assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type)));
859
860 wp = PyObject_NEW(wrapperobject, &wrappertype);
861 if (wp != NULL) {
862 Py_INCREF(descr);
863 wp->descr = descr;
864 Py_INCREF(self);
865 wp->self = self;
866 }
867 return (PyObject *)wp;
868}
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000869
870
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000871/* A built-in 'property' type */
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000872
873/*
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000874 class property(object):
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000875
Tim Peters66c1a522001-09-24 21:17:50 +0000876 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
877 self.__get = fget
878 self.__set = fset
879 self.__del = fdel
880 self.__doc__ = doc
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000881
882 def __get__(self, inst, type=None):
883 if self.__get is None:
884 raise AttributeError, "unreadable attribute"
885 if inst is None:
886 return self
887 return self.__get(inst)
888
889 def __set__(self, inst, value):
Tim Peters66c1a522001-09-24 21:17:50 +0000890 if value is None:
891 if self.__del is None:
892 raise AttributeError, "can't delete attribute"
893 return self.__del(inst)
894 else:
895 if self.__set is None:
896 raise AttributeError, "can't set attribute"
897 return self.__set(inst, value)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000898*/
899
900typedef struct {
901 PyObject_HEAD
Tim Peters66c1a522001-09-24 21:17:50 +0000902 PyObject *prop_get;
903 PyObject *prop_set;
904 PyObject *prop_del;
905 PyObject *prop_doc;
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000906} propertyobject;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000907
Tim Peters66c1a522001-09-24 21:17:50 +0000908static PyMemberDef property_members[] = {
909 {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY},
910 {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY},
911 {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY},
912 {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY},
913 {0}
914};
915
916
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000917static void
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000918property_dealloc(PyObject *self)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000919{
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000920 propertyobject *gs = (propertyobject *)self;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000921
Tim Peters66c1a522001-09-24 21:17:50 +0000922 Py_XDECREF(gs->prop_get);
923 Py_XDECREF(gs->prop_set);
924 Py_XDECREF(gs->prop_del);
925 Py_XDECREF(gs->prop_doc);
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000926 self->ob_type->tp_free(self);
927}
928
929static PyObject *
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000930property_descr_get(PyObject *self, PyObject *obj, PyObject *type)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000931{
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000932 propertyobject *gs = (propertyobject *)self;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000933
Tim Peters66c1a522001-09-24 21:17:50 +0000934 if (gs->prop_get == NULL) {
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000935 PyErr_SetString(PyExc_AttributeError, "unreadable attribute");
936 return NULL;
937 }
938 if (obj == NULL || obj == Py_None) {
939 Py_INCREF(self);
940 return self;
941 }
Tim Peters66c1a522001-09-24 21:17:50 +0000942 return PyObject_CallFunction(gs->prop_get, "(O)", obj);
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000943}
944
945static int
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000946property_descr_set(PyObject *self, PyObject *obj, PyObject *value)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000947{
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000948 propertyobject *gs = (propertyobject *)self;
Guido van Rossum271410a2001-08-24 15:23:20 +0000949 PyObject *func, *res;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000950
Guido van Rossum271410a2001-08-24 15:23:20 +0000951 if (value == NULL)
Tim Peters66c1a522001-09-24 21:17:50 +0000952 func = gs->prop_del;
Guido van Rossum271410a2001-08-24 15:23:20 +0000953 else
Tim Peters66c1a522001-09-24 21:17:50 +0000954 func = gs->prop_set;
Guido van Rossum271410a2001-08-24 15:23:20 +0000955 if (func == NULL) {
956 PyErr_SetString(PyExc_AttributeError,
957 value == NULL ?
958 "can't delete attribute" :
959 "can't set attribute");
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000960 return -1;
961 }
Guido van Rossum845fc482001-08-24 10:17:36 +0000962 if (value == NULL)
Guido van Rossum271410a2001-08-24 15:23:20 +0000963 res = PyObject_CallFunction(func, "(O)", obj);
Guido van Rossum845fc482001-08-24 10:17:36 +0000964 else
Guido van Rossum271410a2001-08-24 15:23:20 +0000965 res = PyObject_CallFunction(func, "(OO)", obj, value);
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000966 if (res == NULL)
967 return -1;
968 Py_DECREF(res);
969 return 0;
970}
971
972static int
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000973property_init(PyObject *self, PyObject *args, PyObject *kwds)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000974{
Tim Peters66c1a522001-09-24 21:17:50 +0000975 PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL;
976 static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0};
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000977 propertyobject *gs = (propertyobject *)self;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000978
Tim Peters66c1a522001-09-24 21:17:50 +0000979 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property",
980 kwlist, &get, &set, &del, &doc))
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000981 return -1;
Tim Peters66c1a522001-09-24 21:17:50 +0000982
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000983 if (get == Py_None)
984 get = NULL;
985 if (set == Py_None)
986 set = NULL;
Tim Peters66c1a522001-09-24 21:17:50 +0000987 if (del == Py_None)
988 del = NULL;
989
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000990 Py_XINCREF(get);
991 Py_XINCREF(set);
Guido van Rossum271410a2001-08-24 15:23:20 +0000992 Py_XINCREF(del);
Tim Peters66c1a522001-09-24 21:17:50 +0000993 Py_XINCREF(doc);
994
995 gs->prop_get = get;
996 gs->prop_set = set;
997 gs->prop_del = del;
998 gs->prop_doc = doc;
999
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001000 return 0;
1001}
1002
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001003static char property_doc[] =
Tim Peters66c1a522001-09-24 21:17:50 +00001004"property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n"
1005"\n"
1006"fget is a function to be used for getting an attribute value, and likewise\n"
1007"fset is a function for setting, and fdel a function for del'ing, an\n"
1008"attribute. Typical use is to define a managed attribute x:\n"
Guido van Rossum91c0d8a2001-08-24 09:55:51 +00001009"class C(object):\n"
1010" def getx(self): return self.__x\n"
1011" def setx(self, value): self.__x = value\n"
Guido van Rossum271410a2001-08-24 15:23:20 +00001012" def delx(self): del self.__x\n"
Tim Peters66c1a522001-09-24 21:17:50 +00001013" x = property(getx, setx, delx, \"I'm the 'x' property.\")";
Guido van Rossum91c0d8a2001-08-24 09:55:51 +00001014
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001015PyTypeObject PyProperty_Type = {
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001016 PyObject_HEAD_INIT(&PyType_Type)
1017 0, /* ob_size */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001018 "property", /* tp_name */
1019 sizeof(propertyobject), /* tp_basicsize */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001020 0, /* tp_itemsize */
1021 /* methods */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001022 property_dealloc, /* tp_dealloc */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001023 0, /* tp_print */
1024 0, /* tp_getattr */
1025 0, /* tp_setattr */
1026 0, /* tp_compare */
1027 0, /* tp_repr */
1028 0, /* tp_as_number */
1029 0, /* tp_as_sequence */
1030 0, /* tp_as_mapping */
1031 0, /* tp_hash */
1032 0, /* tp_call */
1033 0, /* tp_str */
1034 PyObject_GenericGetAttr, /* tp_getattro */
1035 0, /* tp_setattro */
1036 0, /* tp_as_buffer */
Guido van Rossum147b13c2001-08-30 03:10:36 +00001037 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001038 property_doc, /* tp_doc */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001039 0, /* tp_traverse */
1040 0, /* tp_clear */
1041 0, /* tp_richcompare */
1042 0, /* tp_weaklistoffset */
1043 0, /* tp_iter */
1044 0, /* tp_iternext */
1045 0, /* tp_methods */
Tim Peters66c1a522001-09-24 21:17:50 +00001046 property_members, /* tp_members */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001047 0, /* tp_getset */
1048 0, /* tp_base */
1049 0, /* tp_dict */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001050 property_descr_get, /* tp_descr_get */
1051 property_descr_set, /* tp_descr_set */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001052 0, /* tp_dictoffset */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001053 property_init, /* tp_init */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001054 PyType_GenericAlloc, /* tp_alloc */
1055 PyType_GenericNew, /* tp_new */
1056 _PyObject_Del, /* tp_free */
1057};