blob: dfbb3b628f6dd59de17e04869df4334a18f62868 [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;
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;
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 Rossum6f799372001-09-20 20:46:19 +0000305static struct getsetlist method_getset[] = {
306 {"__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
Tim Peters6d6c1a32001-08-02 04:15:00 +0000320static struct getsetlist member_getset[] = {
321 {"__doc__", (getter)member_get_doc},
322 {0}
323};
324
325static PyObject *
326wrapper_get_doc(PyWrapperDescrObject *descr, void *closure)
327{
328 if (descr->d_base->doc == NULL) {
329 Py_INCREF(Py_None);
330 return Py_None;
331 }
332 return PyString_FromString(descr->d_base->doc);
333}
334
335static struct getsetlist wrapper_getset[] = {
336 {"__doc__", (getter)wrapper_get_doc},
337 {0}
338};
339
340static PyTypeObject PyMethodDescr_Type = {
341 PyObject_HEAD_INIT(&PyType_Type)
342 0,
343 "method_descriptor",
344 sizeof(PyMethodDescrObject),
345 0,
346 (destructor)descr_dealloc, /* tp_dealloc */
347 0, /* tp_print */
348 0, /* tp_getattr */
349 0, /* tp_setattr */
350 0, /* tp_compare */
351 (reprfunc)method_repr, /* tp_repr */
352 0, /* tp_as_number */
353 0, /* tp_as_sequence */
354 0, /* tp_as_mapping */
355 0, /* tp_hash */
356 (ternaryfunc)methoddescr_call, /* tp_call */
357 0, /* tp_str */
358 PyObject_GenericGetAttr, /* tp_getattro */
359 0, /* tp_setattro */
360 0, /* tp_as_buffer */
361 Py_TPFLAGS_DEFAULT, /* tp_flags */
362 0, /* tp_doc */
363 0, /* tp_traverse */
364 0, /* tp_clear */
365 0, /* tp_richcompare */
366 0, /* tp_weaklistoffset */
367 0, /* tp_iter */
368 0, /* tp_iternext */
369 0, /* tp_methods */
370 descr_members, /* tp_members */
Guido van Rossum6f799372001-09-20 20:46:19 +0000371 method_getset, /* tp_getset */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000372 0, /* tp_base */
373 0, /* tp_dict */
374 (descrgetfunc)method_get, /* tp_descr_get */
375 0, /* tp_descr_set */
376};
377
378static PyTypeObject PyMemberDescr_Type = {
379 PyObject_HEAD_INIT(&PyType_Type)
380 0,
381 "member_descriptor",
382 sizeof(PyMemberDescrObject),
383 0,
384 (destructor)descr_dealloc, /* tp_dealloc */
385 0, /* tp_print */
386 0, /* tp_getattr */
387 0, /* tp_setattr */
388 0, /* tp_compare */
389 (reprfunc)member_repr, /* tp_repr */
390 0, /* tp_as_number */
391 0, /* tp_as_sequence */
392 0, /* tp_as_mapping */
393 0, /* tp_hash */
394 (ternaryfunc)0, /* tp_call */
395 0, /* tp_str */
396 PyObject_GenericGetAttr, /* tp_getattro */
397 0, /* tp_setattro */
398 0, /* tp_as_buffer */
399 Py_TPFLAGS_DEFAULT, /* tp_flags */
400 0, /* tp_doc */
401 0, /* tp_traverse */
402 0, /* tp_clear */
403 0, /* tp_richcompare */
404 0, /* tp_weaklistoffset */
405 0, /* tp_iter */
406 0, /* tp_iternext */
407 0, /* tp_methods */
408 descr_members, /* tp_members */
Guido van Rossum6f799372001-09-20 20:46:19 +0000409 member_getset, /* tp_getset */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000410 0, /* tp_base */
411 0, /* tp_dict */
412 (descrgetfunc)member_get, /* tp_descr_get */
413 (descrsetfunc)member_set, /* tp_descr_set */
414};
415
416static PyTypeObject PyGetSetDescr_Type = {
417 PyObject_HEAD_INIT(&PyType_Type)
418 0,
419 "getset_descriptor",
420 sizeof(PyGetSetDescrObject),
421 0,
422 (destructor)descr_dealloc, /* tp_dealloc */
423 0, /* tp_print */
424 0, /* tp_getattr */
425 0, /* tp_setattr */
426 0, /* tp_compare */
427 (reprfunc)getset_repr, /* tp_repr */
428 0, /* tp_as_number */
429 0, /* tp_as_sequence */
430 0, /* tp_as_mapping */
431 0, /* tp_hash */
432 (ternaryfunc)0, /* tp_call */
433 0, /* tp_str */
434 PyObject_GenericGetAttr, /* tp_getattro */
435 0, /* tp_setattro */
436 0, /* tp_as_buffer */
437 Py_TPFLAGS_DEFAULT, /* tp_flags */
438 0, /* tp_doc */
439 0, /* tp_traverse */
440 0, /* tp_clear */
441 0, /* tp_richcompare */
442 0, /* tp_weaklistoffset */
443 0, /* tp_iter */
444 0, /* tp_iternext */
445 0, /* tp_methods */
446 descr_members, /* tp_members */
447 0, /* tp_getset */
448 0, /* tp_base */
449 0, /* tp_dict */
450 (descrgetfunc)getset_get, /* tp_descr_get */
451 (descrsetfunc)getset_set, /* tp_descr_set */
452};
453
454static PyTypeObject PyWrapperDescr_Type = {
455 PyObject_HEAD_INIT(&PyType_Type)
456 0,
457 "wrapper_descriptor",
458 sizeof(PyWrapperDescrObject),
459 0,
460 (destructor)descr_dealloc, /* tp_dealloc */
461 0, /* tp_print */
462 0, /* tp_getattr */
463 0, /* tp_setattr */
464 0, /* tp_compare */
465 (reprfunc)wrapper_repr, /* tp_repr */
466 0, /* tp_as_number */
467 0, /* tp_as_sequence */
468 0, /* tp_as_mapping */
469 0, /* tp_hash */
470 (ternaryfunc)wrapperdescr_call, /* tp_call */
471 0, /* tp_str */
472 PyObject_GenericGetAttr, /* tp_getattro */
473 0, /* tp_setattro */
474 0, /* tp_as_buffer */
475 Py_TPFLAGS_DEFAULT, /* tp_flags */
476 0, /* tp_doc */
477 0, /* tp_traverse */
478 0, /* tp_clear */
479 0, /* tp_richcompare */
480 0, /* tp_weaklistoffset */
481 0, /* tp_iter */
482 0, /* tp_iternext */
483 0, /* tp_methods */
484 descr_members, /* tp_members */
485 wrapper_getset, /* tp_getset */
486 0, /* tp_base */
487 0, /* tp_dict */
488 (descrgetfunc)wrapper_get, /* tp_descr_get */
489 0, /* tp_descr_set */
490};
491
492static PyDescrObject *
493descr_new(PyTypeObject *descrtype, PyTypeObject *type, char *name)
494{
495 PyDescrObject *descr;
496
497 descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);
498 if (descr != NULL) {
499 Py_XINCREF(type);
500 descr->d_type = type;
501 descr->d_name = PyString_InternFromString(name);
502 if (descr->d_name == NULL) {
503 Py_DECREF(descr);
504 descr = NULL;
505 }
506 }
507 return descr;
508}
509
510PyObject *
511PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
512{
513 PyMethodDescrObject *descr;
514
515 descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
516 type, method->ml_name);
517 if (descr != NULL)
518 descr->d_method = method;
519 return (PyObject *)descr;
520}
521
522PyObject *
Guido van Rossum6f799372001-09-20 20:46:19 +0000523PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000524{
525 PyMemberDescrObject *descr;
526
527 descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,
528 type, member->name);
529 if (descr != NULL)
530 descr->d_member = member;
531 return (PyObject *)descr;
532}
533
534PyObject *
535PyDescr_NewGetSet(PyTypeObject *type, struct getsetlist *getset)
536{
537 PyGetSetDescrObject *descr;
538
539 descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
540 type, getset->name);
541 if (descr != NULL)
542 descr->d_getset = getset;
543 return (PyObject *)descr;
544}
545
546PyObject *
547PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
548{
549 PyWrapperDescrObject *descr;
550
551 descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
552 type, base->name);
553 if (descr != NULL) {
554 descr->d_base = base;
555 descr->d_wrapped = wrapped;
556 }
557 return (PyObject *)descr;
558}
559
560int
561PyDescr_IsData(PyObject *d)
562{
563 return d->ob_type->tp_descr_set != NULL;
564}
565
566
567/* --- Readonly proxy for dictionaries (actually any mapping) --- */
568
569/* This has no reason to be in this file except that adding new files is a
570 bit of a pain */
571
572typedef struct {
573 PyObject_HEAD
574 PyObject *dict;
575} proxyobject;
576
577static int
578proxy_len(proxyobject *pp)
579{
580 return PyObject_Size(pp->dict);
581}
582
583static PyObject *
584proxy_getitem(proxyobject *pp, PyObject *key)
585{
586 return PyObject_GetItem(pp->dict, key);
587}
588
589static PyMappingMethods proxy_as_mapping = {
590 (inquiry)proxy_len, /* mp_length */
591 (binaryfunc)proxy_getitem, /* mp_subscript */
592 0, /* mp_ass_subscript */
593};
594
595static int
596proxy_contains(proxyobject *pp, PyObject *key)
597{
598 return PySequence_Contains(pp->dict, key);
599}
600
601static PySequenceMethods proxy_as_sequence = {
602 0, /* sq_length */
603 0, /* sq_concat */
604 0, /* sq_repeat */
605 0, /* sq_item */
606 0, /* sq_slice */
607 0, /* sq_ass_item */
608 0, /* sq_ass_slice */
609 (objobjproc)proxy_contains, /* sq_contains */
610 0, /* sq_inplace_concat */
611 0, /* sq_inplace_repeat */
612};
613
614static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000615proxy_has_key(proxyobject *pp, PyObject *key)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000616{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000617 return PyInt_FromLong(PySequence_Contains(pp->dict, key));
618}
619
620static PyObject *
621proxy_get(proxyobject *pp, PyObject *args)
622{
623 PyObject *key, *def = Py_None;
624
625 if (!PyArg_ParseTuple(args, "O|O:get", &key, &def))
626 return NULL;
627 return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
628}
629
630static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000631proxy_keys(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000632{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000633 return PyMapping_Keys(pp->dict);
634}
635
636static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000637proxy_values(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000638{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000639 return PyMapping_Values(pp->dict);
640}
641
642static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000643proxy_items(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000644{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000645 return PyMapping_Items(pp->dict);
646}
647
648static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000649proxy_copy(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000650{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000651 return PyObject_CallMethod(pp->dict, "copy", NULL);
652}
653
654static PyMethodDef proxy_methods[] = {
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000655 {"has_key", (PyCFunction)proxy_has_key, METH_O, "XXX"},
Tim Peters6d6c1a32001-08-02 04:15:00 +0000656 {"get", (PyCFunction)proxy_get, METH_VARARGS, "XXX"},
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000657 {"keys", (PyCFunction)proxy_keys, METH_NOARGS, "XXX"},
658 {"values", (PyCFunction)proxy_values, METH_NOARGS, "XXX"},
659 {"items", (PyCFunction)proxy_items, METH_NOARGS, "XXX"},
660 {"copy", (PyCFunction)proxy_copy, METH_NOARGS, "XXX"},
Tim Peters6d6c1a32001-08-02 04:15:00 +0000661 {0}
662};
663
664static void
665proxy_dealloc(proxyobject *pp)
666{
667 Py_DECREF(pp->dict);
668 PyObject_DEL(pp);
669}
670
671static PyObject *
672proxy_getiter(proxyobject *pp)
673{
674 return PyObject_GetIter(pp->dict);
675}
676
677PyObject *
678proxy_str(proxyobject *pp)
679{
680 return PyObject_Str(pp->dict);
681}
682
683PyTypeObject proxytype = {
684 PyObject_HEAD_INIT(&PyType_Type)
685 0, /* ob_size */
686 "dict-proxy", /* tp_name */
687 sizeof(proxyobject), /* tp_basicsize */
688 0, /* tp_itemsize */
689 /* methods */
690 (destructor)proxy_dealloc, /* tp_dealloc */
691 0, /* tp_print */
692 0, /* tp_getattr */
693 0, /* tp_setattr */
694 0, /* tp_compare */
695 0, /* tp_repr */
696 0, /* tp_as_number */
697 &proxy_as_sequence, /* tp_as_sequence */
698 &proxy_as_mapping, /* tp_as_mapping */
699 0, /* tp_hash */
700 0, /* tp_call */
701 (reprfunc)proxy_str, /* tp_str */
702 PyObject_GenericGetAttr, /* tp_getattro */
703 0, /* tp_setattro */
704 0, /* tp_as_buffer */
705 Py_TPFLAGS_DEFAULT, /* tp_flags */
706 0, /* tp_doc */
707 0, /* tp_traverse */
708 0, /* tp_clear */
709 0, /* tp_richcompare */
710 0, /* tp_weaklistoffset */
711 (getiterfunc)proxy_getiter, /* tp_iter */
712 0, /* tp_iternext */
713 proxy_methods, /* tp_methods */
714 0, /* tp_members */
715 0, /* tp_getset */
716 0, /* tp_base */
717 0, /* tp_dict */
718 0, /* tp_descr_get */
719 0, /* tp_descr_set */
720};
721
722PyObject *
723PyDictProxy_New(PyObject *dict)
724{
725 proxyobject *pp;
726
727 pp = PyObject_NEW(proxyobject, &proxytype);
728 if (pp != NULL) {
729 Py_INCREF(dict);
730 pp->dict = dict;
731 }
732 return (PyObject *)pp;
733}
734
735
736/* --- Wrapper object for "slot" methods --- */
737
738/* This has no reason to be in this file except that adding new files is a
739 bit of a pain */
740
741typedef struct {
742 PyObject_HEAD
743 PyWrapperDescrObject *descr;
744 PyObject *self;
745} wrapperobject;
746
747static void
748wrapper_dealloc(wrapperobject *wp)
749{
750 Py_XDECREF(wp->descr);
751 Py_XDECREF(wp->self);
752 PyObject_DEL(wp);
753}
754
755static PyMethodDef wrapper_methods[] = {
756 {0}
757};
758
759static PyObject *
760wrapper_name(wrapperobject *wp)
761{
762 char *s = wp->descr->d_base->name;
763
764 return PyString_FromString(s);
765}
766
767static PyObject *
768wrapper_doc(wrapperobject *wp)
769{
770 char *s = wp->descr->d_base->doc;
771
772 if (s == NULL) {
773 Py_INCREF(Py_None);
774 return Py_None;
775 }
776 else {
777 return PyString_FromString(s);
778 }
779}
780
781static struct getsetlist wrapper_getsets[] = {
782 {"__name__", (getter)wrapper_name},
783 {"__doc__", (getter)wrapper_doc},
784 {0}
785};
786
787static PyObject *
788wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
789{
790 wrapperfunc wrapper = wp->descr->d_base->wrapper;
791 PyObject *self = wp->self;
792
793 return (*wrapper)(self, args, wp->descr->d_wrapped);
794}
795
796PyTypeObject wrappertype = {
797 PyObject_HEAD_INIT(&PyType_Type)
798 0, /* ob_size */
799 "method-wrapper", /* tp_name */
800 sizeof(wrapperobject), /* tp_basicsize */
801 0, /* tp_itemsize */
802 /* methods */
803 (destructor)wrapper_dealloc, /* tp_dealloc */
804 0, /* tp_print */
805 0, /* tp_getattr */
806 0, /* tp_setattr */
807 0, /* tp_compare */
808 0, /* tp_repr */
809 0, /* tp_as_number */
810 0, /* tp_as_sequence */
811 0, /* tp_as_mapping */
812 0, /* tp_hash */
813 (ternaryfunc)wrapper_call, /* tp_call */
814 0, /* tp_str */
815 PyObject_GenericGetAttr, /* tp_getattro */
816 0, /* tp_setattro */
817 0, /* tp_as_buffer */
818 Py_TPFLAGS_DEFAULT, /* tp_flags */
819 0, /* tp_doc */
820 0, /* tp_traverse */
821 0, /* tp_clear */
822 0, /* tp_richcompare */
823 0, /* tp_weaklistoffset */
824 0, /* tp_iter */
825 0, /* tp_iternext */
826 wrapper_methods, /* tp_methods */
827 0, /* tp_members */
828 wrapper_getsets, /* tp_getset */
829 0, /* tp_base */
830 0, /* tp_dict */
831 0, /* tp_descr_get */
832 0, /* tp_descr_set */
833};
834
835PyObject *
836PyWrapper_New(PyObject *d, PyObject *self)
837{
838 wrapperobject *wp;
839 PyWrapperDescrObject *descr;
840
841 assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));
842 descr = (PyWrapperDescrObject *)d;
843 assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type)));
844
845 wp = PyObject_NEW(wrapperobject, &wrappertype);
846 if (wp != NULL) {
847 Py_INCREF(descr);
848 wp->descr = descr;
849 Py_INCREF(self);
850 wp->self = self;
851 }
852 return (PyObject *)wp;
853}
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000854
855
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000856/* A built-in 'property' type */
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000857
858/*
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000859 class property(object):
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000860
861 def __init__(self, get=None, set=None):
862 self.__get = get
863 self.__set = set
864
865 def __get__(self, inst, type=None):
866 if self.__get is None:
867 raise AttributeError, "unreadable attribute"
868 if inst is None:
869 return self
870 return self.__get(inst)
871
872 def __set__(self, inst, value):
873 if self.__set is None:
874 raise AttributeError, "unsettable attribute"
875 return self.__set(inst, value)
876*/
877
878typedef struct {
879 PyObject_HEAD
880 PyObject *get;
881 PyObject *set;
Guido van Rossum271410a2001-08-24 15:23:20 +0000882 PyObject *del;
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000883} propertyobject;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000884
885static void
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000886property_dealloc(PyObject *self)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000887{
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000888 propertyobject *gs = (propertyobject *)self;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000889
890 Py_XDECREF(gs->get);
891 Py_XDECREF(gs->set);
Guido van Rossum271410a2001-08-24 15:23:20 +0000892 Py_XDECREF(gs->del);
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000893 self->ob_type->tp_free(self);
894}
895
896static PyObject *
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000897property_descr_get(PyObject *self, PyObject *obj, PyObject *type)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000898{
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000899 propertyobject *gs = (propertyobject *)self;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000900
901 if (gs->get == NULL) {
902 PyErr_SetString(PyExc_AttributeError, "unreadable attribute");
903 return NULL;
904 }
905 if (obj == NULL || obj == Py_None) {
906 Py_INCREF(self);
907 return self;
908 }
909 return PyObject_CallFunction(gs->get, "(O)", obj);
910}
911
912static int
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000913property_descr_set(PyObject *self, PyObject *obj, PyObject *value)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000914{
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000915 propertyobject *gs = (propertyobject *)self;
Guido van Rossum271410a2001-08-24 15:23:20 +0000916 PyObject *func, *res;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000917
Guido van Rossum271410a2001-08-24 15:23:20 +0000918 if (value == NULL)
919 func = gs->del;
920 else
921 func = gs->set;
922 if (func == NULL) {
923 PyErr_SetString(PyExc_AttributeError,
924 value == NULL ?
925 "can't delete attribute" :
926 "can't set attribute");
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000927 return -1;
928 }
Guido van Rossum845fc482001-08-24 10:17:36 +0000929 if (value == NULL)
Guido van Rossum271410a2001-08-24 15:23:20 +0000930 res = PyObject_CallFunction(func, "(O)", obj);
Guido van Rossum845fc482001-08-24 10:17:36 +0000931 else
Guido van Rossum271410a2001-08-24 15:23:20 +0000932 res = PyObject_CallFunction(func, "(OO)", obj, value);
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000933 if (res == NULL)
934 return -1;
935 Py_DECREF(res);
936 return 0;
937}
938
939static int
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000940property_init(PyObject *self, PyObject *args, PyObject *kwds)
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000941{
Guido van Rossum271410a2001-08-24 15:23:20 +0000942 PyObject *get = NULL, *set = NULL, *del = NULL;
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000943 propertyobject *gs = (propertyobject *)self;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000944
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000945 if (!PyArg_ParseTuple(args, "|OOO:property", &get, &set, &del))
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000946 return -1;
947 if (get == Py_None)
948 get = NULL;
949 if (set == Py_None)
950 set = NULL;
951 Py_XINCREF(get);
952 Py_XINCREF(set);
Guido van Rossum271410a2001-08-24 15:23:20 +0000953 Py_XINCREF(del);
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000954 gs->get = get;
955 gs->set = set;
Guido van Rossum271410a2001-08-24 15:23:20 +0000956 gs->del = del;
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000957 return 0;
958}
959
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000960static char property_doc[] =
961"property([getfunc[, setfunc[, delfunc]]]) -> property attribute\n"
Guido van Rossum91c0d8a2001-08-24 09:55:51 +0000962"Typical use to define a managed attribute x of C instances:\n"
963"class C(object):\n"
964" def getx(self): return self.__x\n"
965" def setx(self, value): self.__x = value\n"
Guido van Rossum271410a2001-08-24 15:23:20 +0000966" def delx(self): del self.__x\n"
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000967" x = property(getx, setx, delx)";
Guido van Rossum91c0d8a2001-08-24 09:55:51 +0000968
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000969PyTypeObject PyProperty_Type = {
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000970 PyObject_HEAD_INIT(&PyType_Type)
971 0, /* ob_size */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000972 "property", /* tp_name */
973 sizeof(propertyobject), /* tp_basicsize */
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000974 0, /* tp_itemsize */
975 /* methods */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000976 property_dealloc, /* tp_dealloc */
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000977 0, /* tp_print */
978 0, /* tp_getattr */
979 0, /* tp_setattr */
980 0, /* tp_compare */
981 0, /* tp_repr */
982 0, /* tp_as_number */
983 0, /* tp_as_sequence */
984 0, /* tp_as_mapping */
985 0, /* tp_hash */
986 0, /* tp_call */
987 0, /* tp_str */
988 PyObject_GenericGetAttr, /* tp_getattro */
989 0, /* tp_setattro */
990 0, /* tp_as_buffer */
Guido van Rossum147b13c2001-08-30 03:10:36 +0000991 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +0000992 property_doc, /* tp_doc */
Guido van Rossum29a62dd2001-08-23 21:40:38 +0000993 0, /* tp_traverse */
994 0, /* tp_clear */
995 0, /* tp_richcompare */
996 0, /* tp_weaklistoffset */
997 0, /* tp_iter */
998 0, /* tp_iternext */
999 0, /* tp_methods */
1000 0, /* tp_members */
1001 0, /* tp_getset */
1002 0, /* tp_base */
1003 0, /* tp_dict */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001004 property_descr_get, /* tp_descr_get */
1005 property_descr_set, /* tp_descr_set */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001006 0, /* tp_dictoffset */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001007 property_init, /* tp_init */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001008 PyType_GenericAlloc, /* tp_alloc */
1009 PyType_GenericNew, /* tp_new */
1010 _PyObject_Del, /* tp_free */
1011};