blob: 761e1ab854c0e858024efb33e95697428dcecbe7 [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
Tim Peters6d6c1a32001-08-02 04:15:00 +00006static void
7descr_dealloc(PyDescrObject *descr)
8{
Guido van Rossum048eb752001-10-02 21:24:57 +00009 _PyObject_GC_UNTRACK(descr);
Tim Peters6d6c1a32001-08-02 04:15:00 +000010 Py_XDECREF(descr->d_type);
11 Py_XDECREF(descr->d_name);
Guido van Rossum048eb752001-10-02 21:24:57 +000012 PyObject_GC_Del(descr);
Tim Peters6d6c1a32001-08-02 04:15:00 +000013}
14
15static char *
16descr_name(PyDescrObject *descr)
17{
18 if (descr->d_name != NULL && PyString_Check(descr->d_name))
19 return PyString_AS_STRING(descr->d_name);
20 else
21 return "?";
22}
23
24static PyObject *
25descr_repr(PyDescrObject *descr, char *format)
26{
Barry Warsaw7ce36942001-08-24 18:34:26 +000027 return PyString_FromFormat(format, descr_name(descr),
28 descr->d_type->tp_name);
Tim Peters6d6c1a32001-08-02 04:15:00 +000029}
30
31static PyObject *
32method_repr(PyMethodDescrObject *descr)
33{
34 return descr_repr((PyDescrObject *)descr,
Barry Warsaw7ce36942001-08-24 18:34:26 +000035 "<method '%s' of '%s' objects>");
Tim Peters6d6c1a32001-08-02 04:15:00 +000036}
37
38static PyObject *
39member_repr(PyMemberDescrObject *descr)
40{
41 return descr_repr((PyDescrObject *)descr,
Barry Warsaw7ce36942001-08-24 18:34:26 +000042 "<member '%s' of '%s' objects>");
Tim Peters6d6c1a32001-08-02 04:15:00 +000043}
44
45static PyObject *
46getset_repr(PyGetSetDescrObject *descr)
47{
48 return descr_repr((PyDescrObject *)descr,
Barry Warsaw7ce36942001-08-24 18:34:26 +000049 "<attribute '%s' of '%s' objects>");
Tim Peters6d6c1a32001-08-02 04:15:00 +000050}
51
52static PyObject *
53wrapper_repr(PyWrapperDescrObject *descr)
54{
55 return descr_repr((PyDescrObject *)descr,
Barry Warsaw7ce36942001-08-24 18:34:26 +000056 "<slot wrapper '%s' of '%s' objects>");
Tim Peters6d6c1a32001-08-02 04:15:00 +000057}
58
59static int
60descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
Guido van Rossum8098ddb2001-08-16 08:27:33 +000061 PyObject **pres)
Tim Peters6d6c1a32001-08-02 04:15:00 +000062{
Guido van Rossum8098ddb2001-08-16 08:27:33 +000063 if (obj == NULL || (obj == Py_None && type != Py_None->ob_type)) {
Tim Peters6d6c1a32001-08-02 04:15:00 +000064 Py_INCREF(descr);
65 *pres = (PyObject *)descr;
66 return 1;
67 }
Guido van Rossumc588e902002-08-19 16:02:33 +000068 if (!PyObject_TypeCheck(obj, descr->d_type)) {
Tim Peters6d6c1a32001-08-02 04:15:00 +000069 PyErr_Format(PyExc_TypeError,
Barry Warsaw7ce36942001-08-24 18:34:26 +000070 "descriptor '%s' for '%s' objects "
71 "doesn't apply to '%s' object",
Tim Peters6d6c1a32001-08-02 04:15:00 +000072 descr_name((PyDescrObject *)descr),
73 descr->d_type->tp_name,
74 obj->ob_type->tp_name);
75 *pres = NULL;
76 return 1;
77 }
78 return 0;
79}
80
81static PyObject *
Tim Petersbca1cbc2002-12-09 22:56:13 +000082classmethod_get(PyMethodDescrObject *descr, PyObject *obj,
83 PyTypeObject *type)
84{
85 return PyCFunction_New(descr->d_method, (PyObject *)type);
86}
87
88static PyObject *
Tim Peters6d6c1a32001-08-02 04:15:00 +000089method_get(PyMethodDescrObject *descr, PyObject *obj, PyTypeObject *type)
90{
91 PyObject *res;
92
93 if (descr_check((PyDescrObject *)descr, obj, type, &res))
94 return res;
95 return PyCFunction_New(descr->d_method, obj);
96}
97
98static PyObject *
99member_get(PyMemberDescrObject *descr, PyObject *obj, PyTypeObject *type)
100{
101 PyObject *res;
102
103 if (descr_check((PyDescrObject *)descr, obj, type, &res))
104 return res;
Guido van Rossum6f799372001-09-20 20:46:19 +0000105 return PyMember_GetOne((char *)obj, descr->d_member);
Tim Peters6d6c1a32001-08-02 04:15:00 +0000106}
107
108static PyObject *
109getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
110{
111 PyObject *res;
112
113 if (descr_check((PyDescrObject *)descr, obj, type, &res))
114 return res;
115 if (descr->d_getset->get != NULL)
116 return descr->d_getset->get(obj, descr->d_getset->closure);
117 PyErr_Format(PyExc_TypeError,
Guido van Rossum2b8235e2001-12-15 05:00:30 +0000118 "attribute '%.300s' of '%.100s' objects is not readable",
Tim Peters6d6c1a32001-08-02 04:15:00 +0000119 descr_name((PyDescrObject *)descr),
120 descr->d_type->tp_name);
121 return NULL;
122}
123
124static PyObject *
125wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyTypeObject *type)
126{
127 PyObject *res;
128
129 if (descr_check((PyDescrObject *)descr, obj, type, &res))
130 return res;
131 return PyWrapper_New((PyObject *)descr, obj);
132}
133
134static int
135descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,
136 int *pres)
137{
138 assert(obj != NULL);
139 if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
140 PyErr_Format(PyExc_TypeError,
141 "descriptor '%.200s' for '%.100s' objects "
142 "doesn't apply to '%.100s' object",
143 descr_name(descr),
144 descr->d_type->tp_name,
145 obj->ob_type->tp_name);
146 *pres = -1;
147 return 1;
148 }
149 return 0;
150}
151
152static int
153member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)
154{
155 int res;
156
157 if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
158 return res;
Guido van Rossum6f799372001-09-20 20:46:19 +0000159 return PyMember_SetOne((char *)obj, descr->d_member, value);
Tim Peters6d6c1a32001-08-02 04:15:00 +0000160}
161
162static int
163getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
164{
165 int res;
166
167 if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
168 return res;
169 if (descr->d_getset->set != NULL)
170 return descr->d_getset->set(obj, value,
171 descr->d_getset->closure);
172 PyErr_Format(PyExc_TypeError,
Guido van Rossum2b8235e2001-12-15 05:00:30 +0000173 "attribute '%.300s' of '%.100s' objects is not writable",
Tim Peters6d6c1a32001-08-02 04:15:00 +0000174 descr_name((PyDescrObject *)descr),
175 descr->d_type->tp_name);
176 return -1;
177}
178
179static PyObject *
180methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
181{
182 int argc;
183 PyObject *self, *func, *result;
184
185 /* Make sure that the first argument is acceptable as 'self' */
186 assert(PyTuple_Check(args));
187 argc = PyTuple_GET_SIZE(args);
188 if (argc < 1) {
189 PyErr_Format(PyExc_TypeError,
190 "descriptor '%.300s' of '%.100s' "
191 "object needs an argument",
192 descr_name((PyDescrObject *)descr),
193 descr->d_type->tp_name);
194 return NULL;
195 }
196 self = PyTuple_GET_ITEM(args, 0);
197 if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
198 PyErr_Format(PyExc_TypeError,
199 "descriptor '%.200s' "
200 "requires a '%.100s' object "
201 "but received a '%.100s'",
202 descr_name((PyDescrObject *)descr),
203 descr->d_type->tp_name,
204 self->ob_type->tp_name);
205 return NULL;
206 }
207
208 func = PyCFunction_New(descr->d_method, self);
209 if (func == NULL)
210 return NULL;
211 args = PyTuple_GetSlice(args, 1, argc);
212 if (args == NULL) {
213 Py_DECREF(func);
214 return NULL;
215 }
216 result = PyEval_CallObjectWithKeywords(func, args, kwds);
217 Py_DECREF(args);
218 Py_DECREF(func);
219 return result;
220}
221
222static PyObject *
Tim Petersbca1cbc2002-12-09 22:56:13 +0000223classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
224 PyObject *kwds)
225{
226 PyObject *func, *result;
227
228 func = PyCFunction_New(descr->d_method, (PyObject *)descr->d_type);
229 if (func == NULL)
230 return NULL;
231
232 result = PyEval_CallObjectWithKeywords(func, args, kwds);
233 Py_DECREF(func);
234 return result;
235}
236
237static PyObject *
Tim Peters6d6c1a32001-08-02 04:15:00 +0000238wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
239{
240 int argc;
241 PyObject *self, *func, *result;
242
243 /* Make sure that the first argument is acceptable as 'self' */
244 assert(PyTuple_Check(args));
245 argc = PyTuple_GET_SIZE(args);
246 if (argc < 1) {
247 PyErr_Format(PyExc_TypeError,
248 "descriptor '%.300s' of '%.100s' "
249 "object needs an argument",
250 descr_name((PyDescrObject *)descr),
251 descr->d_type->tp_name);
252 return NULL;
253 }
254 self = PyTuple_GET_ITEM(args, 0);
255 if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
256 PyErr_Format(PyExc_TypeError,
257 "descriptor '%.200s' "
258 "requires a '%.100s' object "
259 "but received a '%.100s'",
260 descr_name((PyDescrObject *)descr),
261 descr->d_type->tp_name,
262 self->ob_type->tp_name);
263 return NULL;
264 }
265
266 func = PyWrapper_New((PyObject *)descr, self);
267 if (func == NULL)
268 return NULL;
269 args = PyTuple_GetSlice(args, 1, argc);
270 if (args == NULL) {
271 Py_DECREF(func);
272 return NULL;
273 }
274 result = PyEval_CallObjectWithKeywords(func, args, kwds);
275 Py_DECREF(args);
276 Py_DECREF(func);
277 return result;
278}
279
280static PyObject *
Guido van Rossum6f799372001-09-20 20:46:19 +0000281method_get_doc(PyMethodDescrObject *descr, void *closure)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000282{
283 if (descr->d_method->ml_doc == NULL) {
284 Py_INCREF(Py_None);
285 return Py_None;
286 }
287 return PyString_FromString(descr->d_method->ml_doc);
288}
289
Guido van Rossum6f799372001-09-20 20:46:19 +0000290static PyMemberDef descr_members[] = {
Tim Peters6d6c1a32001-08-02 04:15:00 +0000291 {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},
292 {"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},
293 {0}
294};
295
Guido van Rossum32d34c82001-09-20 21:45:26 +0000296static PyGetSetDef method_getset[] = {
Guido van Rossum6f799372001-09-20 20:46:19 +0000297 {"__doc__", (getter)method_get_doc},
298 {0}
299};
300
301static PyObject *
302member_get_doc(PyMemberDescrObject *descr, void *closure)
303{
304 if (descr->d_member->doc == NULL) {
305 Py_INCREF(Py_None);
306 return Py_None;
307 }
308 return PyString_FromString(descr->d_member->doc);
309}
310
Guido van Rossum32d34c82001-09-20 21:45:26 +0000311static PyGetSetDef member_getset[] = {
Tim Peters6d6c1a32001-08-02 04:15:00 +0000312 {"__doc__", (getter)member_get_doc},
313 {0}
314};
315
316static PyObject *
Guido van Rossum32d34c82001-09-20 21:45:26 +0000317getset_get_doc(PyGetSetDescrObject *descr, void *closure)
318{
319 if (descr->d_getset->doc == NULL) {
320 Py_INCREF(Py_None);
321 return Py_None;
322 }
323 return PyString_FromString(descr->d_getset->doc);
324}
325
326static PyGetSetDef getset_getset[] = {
327 {"__doc__", (getter)getset_get_doc},
328 {0}
329};
330
331static PyObject *
Tim Peters6d6c1a32001-08-02 04:15:00 +0000332wrapper_get_doc(PyWrapperDescrObject *descr, void *closure)
333{
334 if (descr->d_base->doc == NULL) {
335 Py_INCREF(Py_None);
336 return Py_None;
337 }
338 return PyString_FromString(descr->d_base->doc);
339}
340
Guido van Rossum32d34c82001-09-20 21:45:26 +0000341static PyGetSetDef wrapper_getset[] = {
Tim Peters6d6c1a32001-08-02 04:15:00 +0000342 {"__doc__", (getter)wrapper_get_doc},
343 {0}
344};
345
Guido van Rossum048eb752001-10-02 21:24:57 +0000346static int
347descr_traverse(PyObject *self, visitproc visit, void *arg)
348{
349 PyDescrObject *descr = (PyDescrObject *)self;
350 int err;
351
352 if (descr->d_type) {
353 err = visit((PyObject *)(descr->d_type), arg);
354 if (err)
355 return err;
356 }
357 return 0;
358}
359
Tim Peters6d6c1a32001-08-02 04:15:00 +0000360static PyTypeObject PyMethodDescr_Type = {
361 PyObject_HEAD_INIT(&PyType_Type)
362 0,
363 "method_descriptor",
364 sizeof(PyMethodDescrObject),
365 0,
366 (destructor)descr_dealloc, /* tp_dealloc */
367 0, /* tp_print */
368 0, /* tp_getattr */
369 0, /* tp_setattr */
370 0, /* tp_compare */
371 (reprfunc)method_repr, /* tp_repr */
372 0, /* tp_as_number */
373 0, /* tp_as_sequence */
374 0, /* tp_as_mapping */
375 0, /* tp_hash */
376 (ternaryfunc)methoddescr_call, /* tp_call */
377 0, /* tp_str */
378 PyObject_GenericGetAttr, /* tp_getattro */
379 0, /* tp_setattro */
380 0, /* tp_as_buffer */
Guido van Rossum048eb752001-10-02 21:24:57 +0000381 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000382 0, /* tp_doc */
Guido van Rossum048eb752001-10-02 21:24:57 +0000383 descr_traverse, /* tp_traverse */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000384 0, /* tp_clear */
385 0, /* tp_richcompare */
386 0, /* tp_weaklistoffset */
387 0, /* tp_iter */
388 0, /* tp_iternext */
389 0, /* tp_methods */
390 descr_members, /* tp_members */
Guido van Rossum6f799372001-09-20 20:46:19 +0000391 method_getset, /* tp_getset */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000392 0, /* tp_base */
393 0, /* tp_dict */
394 (descrgetfunc)method_get, /* tp_descr_get */
395 0, /* tp_descr_set */
396};
397
Tim Petersbca1cbc2002-12-09 22:56:13 +0000398static PyTypeObject PyClassMethodDescr_Type = {
399 PyObject_HEAD_INIT(&PyType_Type)
400 0,
401 "special_method_descriptor",
402 sizeof(PyMethodDescrObject),
403 0,
404 (destructor)descr_dealloc, /* tp_dealloc */
405 0, /* tp_print */
406 0, /* tp_getattr */
407 0, /* tp_setattr */
408 0, /* tp_compare */
409 (reprfunc)method_repr, /* tp_repr */
410 0, /* tp_as_number */
411 0, /* tp_as_sequence */
412 0, /* tp_as_mapping */
413 0, /* tp_hash */
414 (ternaryfunc)classmethoddescr_call, /* tp_call */
415 0, /* tp_str */
416 PyObject_GenericGetAttr, /* tp_getattro */
417 0, /* tp_setattro */
418 0, /* tp_as_buffer */
419 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
420 0, /* tp_doc */
421 descr_traverse, /* tp_traverse */
422 0, /* tp_clear */
423 0, /* tp_richcompare */
424 0, /* tp_weaklistoffset */
425 0, /* tp_iter */
426 0, /* tp_iternext */
427 0, /* tp_methods */
428 descr_members, /* tp_members */
429 method_getset, /* tp_getset */
430 0, /* tp_base */
431 0, /* tp_dict */
432 (descrgetfunc)classmethod_get, /* tp_descr_get */
433 0, /* tp_descr_set */
434};
435
Tim Peters6d6c1a32001-08-02 04:15:00 +0000436static PyTypeObject PyMemberDescr_Type = {
437 PyObject_HEAD_INIT(&PyType_Type)
438 0,
439 "member_descriptor",
440 sizeof(PyMemberDescrObject),
441 0,
442 (destructor)descr_dealloc, /* tp_dealloc */
443 0, /* tp_print */
444 0, /* tp_getattr */
445 0, /* tp_setattr */
446 0, /* tp_compare */
447 (reprfunc)member_repr, /* tp_repr */
448 0, /* tp_as_number */
449 0, /* tp_as_sequence */
450 0, /* tp_as_mapping */
451 0, /* tp_hash */
452 (ternaryfunc)0, /* tp_call */
453 0, /* tp_str */
454 PyObject_GenericGetAttr, /* tp_getattro */
455 0, /* tp_setattro */
456 0, /* tp_as_buffer */
Guido van Rossum048eb752001-10-02 21:24:57 +0000457 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000458 0, /* tp_doc */
Guido van Rossum048eb752001-10-02 21:24:57 +0000459 descr_traverse, /* tp_traverse */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000460 0, /* tp_clear */
461 0, /* tp_richcompare */
462 0, /* tp_weaklistoffset */
463 0, /* tp_iter */
464 0, /* tp_iternext */
465 0, /* tp_methods */
466 descr_members, /* tp_members */
Guido van Rossum6f799372001-09-20 20:46:19 +0000467 member_getset, /* tp_getset */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000468 0, /* tp_base */
469 0, /* tp_dict */
470 (descrgetfunc)member_get, /* tp_descr_get */
471 (descrsetfunc)member_set, /* tp_descr_set */
472};
473
474static PyTypeObject PyGetSetDescr_Type = {
475 PyObject_HEAD_INIT(&PyType_Type)
476 0,
477 "getset_descriptor",
478 sizeof(PyGetSetDescrObject),
479 0,
480 (destructor)descr_dealloc, /* tp_dealloc */
481 0, /* tp_print */
482 0, /* tp_getattr */
483 0, /* tp_setattr */
484 0, /* tp_compare */
485 (reprfunc)getset_repr, /* tp_repr */
486 0, /* tp_as_number */
487 0, /* tp_as_sequence */
488 0, /* tp_as_mapping */
489 0, /* tp_hash */
490 (ternaryfunc)0, /* tp_call */
491 0, /* tp_str */
492 PyObject_GenericGetAttr, /* tp_getattro */
493 0, /* tp_setattro */
494 0, /* tp_as_buffer */
Guido van Rossum048eb752001-10-02 21:24:57 +0000495 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000496 0, /* tp_doc */
Guido van Rossum048eb752001-10-02 21:24:57 +0000497 descr_traverse, /* tp_traverse */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000498 0, /* tp_clear */
499 0, /* tp_richcompare */
500 0, /* tp_weaklistoffset */
501 0, /* tp_iter */
502 0, /* tp_iternext */
503 0, /* tp_methods */
504 descr_members, /* tp_members */
Guido van Rossum32d34c82001-09-20 21:45:26 +0000505 getset_getset, /* tp_getset */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000506 0, /* tp_base */
507 0, /* tp_dict */
508 (descrgetfunc)getset_get, /* tp_descr_get */
509 (descrsetfunc)getset_set, /* tp_descr_set */
510};
511
Guido van Rossumf4593e02001-10-03 12:09:30 +0000512PyTypeObject PyWrapperDescr_Type = {
Tim Peters6d6c1a32001-08-02 04:15:00 +0000513 PyObject_HEAD_INIT(&PyType_Type)
514 0,
515 "wrapper_descriptor",
516 sizeof(PyWrapperDescrObject),
517 0,
518 (destructor)descr_dealloc, /* tp_dealloc */
519 0, /* tp_print */
520 0, /* tp_getattr */
521 0, /* tp_setattr */
522 0, /* tp_compare */
523 (reprfunc)wrapper_repr, /* tp_repr */
524 0, /* tp_as_number */
525 0, /* tp_as_sequence */
526 0, /* tp_as_mapping */
527 0, /* tp_hash */
528 (ternaryfunc)wrapperdescr_call, /* tp_call */
529 0, /* tp_str */
530 PyObject_GenericGetAttr, /* tp_getattro */
531 0, /* tp_setattro */
532 0, /* tp_as_buffer */
Guido van Rossum048eb752001-10-02 21:24:57 +0000533 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000534 0, /* tp_doc */
Guido van Rossum048eb752001-10-02 21:24:57 +0000535 descr_traverse, /* tp_traverse */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000536 0, /* tp_clear */
537 0, /* tp_richcompare */
538 0, /* tp_weaklistoffset */
539 0, /* tp_iter */
540 0, /* tp_iternext */
541 0, /* tp_methods */
542 descr_members, /* tp_members */
543 wrapper_getset, /* tp_getset */
544 0, /* tp_base */
545 0, /* tp_dict */
546 (descrgetfunc)wrapper_get, /* tp_descr_get */
547 0, /* tp_descr_set */
548};
549
550static PyDescrObject *
551descr_new(PyTypeObject *descrtype, PyTypeObject *type, char *name)
552{
553 PyDescrObject *descr;
554
555 descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);
556 if (descr != NULL) {
557 Py_XINCREF(type);
558 descr->d_type = type;
559 descr->d_name = PyString_InternFromString(name);
560 if (descr->d_name == NULL) {
561 Py_DECREF(descr);
562 descr = NULL;
563 }
564 }
565 return descr;
566}
567
568PyObject *
569PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
570{
571 PyMethodDescrObject *descr;
572
573 descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
574 type, method->ml_name);
575 if (descr != NULL)
576 descr->d_method = method;
577 return (PyObject *)descr;
578}
579
580PyObject *
Tim Petersbca1cbc2002-12-09 22:56:13 +0000581PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)
582{
583 PyMethodDescrObject *descr;
584
585 descr = (PyMethodDescrObject *)descr_new(&PyClassMethodDescr_Type,
586 type, method->ml_name);
587 if (descr != NULL)
588 descr->d_method = method;
589 return (PyObject *)descr;
590}
591
592PyObject *
Guido van Rossum6f799372001-09-20 20:46:19 +0000593PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000594{
595 PyMemberDescrObject *descr;
596
597 descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,
598 type, member->name);
599 if (descr != NULL)
600 descr->d_member = member;
601 return (PyObject *)descr;
602}
603
604PyObject *
Guido van Rossum32d34c82001-09-20 21:45:26 +0000605PyDescr_NewGetSet(PyTypeObject *type, PyGetSetDef *getset)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000606{
607 PyGetSetDescrObject *descr;
608
609 descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
610 type, getset->name);
611 if (descr != NULL)
612 descr->d_getset = getset;
613 return (PyObject *)descr;
614}
615
616PyObject *
617PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
618{
619 PyWrapperDescrObject *descr;
620
621 descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
622 type, base->name);
623 if (descr != NULL) {
624 descr->d_base = base;
625 descr->d_wrapped = wrapped;
626 }
627 return (PyObject *)descr;
628}
629
Tim Peters6d6c1a32001-08-02 04:15:00 +0000630
631/* --- Readonly proxy for dictionaries (actually any mapping) --- */
632
633/* This has no reason to be in this file except that adding new files is a
634 bit of a pain */
635
636typedef struct {
637 PyObject_HEAD
638 PyObject *dict;
639} proxyobject;
640
641static int
642proxy_len(proxyobject *pp)
643{
644 return PyObject_Size(pp->dict);
645}
646
647static PyObject *
648proxy_getitem(proxyobject *pp, PyObject *key)
649{
650 return PyObject_GetItem(pp->dict, key);
651}
652
653static PyMappingMethods proxy_as_mapping = {
654 (inquiry)proxy_len, /* mp_length */
655 (binaryfunc)proxy_getitem, /* mp_subscript */
656 0, /* mp_ass_subscript */
657};
658
659static int
660proxy_contains(proxyobject *pp, PyObject *key)
661{
662 return PySequence_Contains(pp->dict, key);
663}
664
665static PySequenceMethods proxy_as_sequence = {
666 0, /* sq_length */
667 0, /* sq_concat */
668 0, /* sq_repeat */
669 0, /* sq_item */
670 0, /* sq_slice */
671 0, /* sq_ass_item */
672 0, /* sq_ass_slice */
673 (objobjproc)proxy_contains, /* sq_contains */
674 0, /* sq_inplace_concat */
675 0, /* sq_inplace_repeat */
676};
677
678static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000679proxy_has_key(proxyobject *pp, PyObject *key)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000680{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000681 return PyInt_FromLong(PySequence_Contains(pp->dict, key));
682}
683
684static PyObject *
685proxy_get(proxyobject *pp, PyObject *args)
686{
687 PyObject *key, *def = Py_None;
688
689 if (!PyArg_ParseTuple(args, "O|O:get", &key, &def))
690 return NULL;
691 return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
692}
693
694static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000695proxy_keys(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000696{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000697 return PyMapping_Keys(pp->dict);
698}
699
700static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000701proxy_values(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000702{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000703 return PyMapping_Values(pp->dict);
704}
705
706static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000707proxy_items(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000708{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000709 return PyMapping_Items(pp->dict);
710}
711
712static PyObject *
Walter Dörwalde990c792002-03-25 17:43:22 +0000713proxy_iterkeys(proxyobject *pp)
714{
715 return PyObject_CallMethod(pp->dict, "iterkeys", NULL);
716}
717
718static PyObject *
719proxy_itervalues(proxyobject *pp)
720{
721 return PyObject_CallMethod(pp->dict, "itervalues", NULL);
722}
723
724static PyObject *
725proxy_iteritems(proxyobject *pp)
726{
727 return PyObject_CallMethod(pp->dict, "iteritems", NULL);
728}
729static PyObject *
Martin v. Löwise3eb1f22001-08-16 13:15:00 +0000730proxy_copy(proxyobject *pp)
Tim Peters6d6c1a32001-08-02 04:15:00 +0000731{
Tim Peters6d6c1a32001-08-02 04:15:00 +0000732 return PyObject_CallMethod(pp->dict, "copy", NULL);
733}
734
735static PyMethodDef proxy_methods[] = {
Guido van Rossum59610422002-04-13 14:06:36 +0000736 {"has_key", (PyCFunction)proxy_has_key, METH_O,
Neal Norwitz5dc2a372002-08-13 22:19:13 +0000737 PyDoc_STR("D.has_key(k) -> 1 if D has a key k, else 0")},
Guido van Rossum59610422002-04-13 14:06:36 +0000738 {"get", (PyCFunction)proxy_get, METH_VARARGS,
Neal Norwitz5dc2a372002-08-13 22:19:13 +0000739 PyDoc_STR("D.get(k[,d]) -> D[k] if D.has_key(k), else d."
740 " d defaults to None.")},
Guido van Rossum59610422002-04-13 14:06:36 +0000741 {"keys", (PyCFunction)proxy_keys, METH_NOARGS,
Neal Norwitz5dc2a372002-08-13 22:19:13 +0000742 PyDoc_STR("D.keys() -> list of D's keys")},
Guido van Rossum59610422002-04-13 14:06:36 +0000743 {"values", (PyCFunction)proxy_values, METH_NOARGS,
Neal Norwitz5dc2a372002-08-13 22:19:13 +0000744 PyDoc_STR("D.values() -> list of D's values")},
Guido van Rossum59610422002-04-13 14:06:36 +0000745 {"items", (PyCFunction)proxy_items, METH_NOARGS,
Neal Norwitz5dc2a372002-08-13 22:19:13 +0000746 PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")},
Guido van Rossum59610422002-04-13 14:06:36 +0000747 {"iterkeys", (PyCFunction)proxy_iterkeys, METH_NOARGS,
Neal Norwitz5dc2a372002-08-13 22:19:13 +0000748 PyDoc_STR("D.iterkeys() -> an iterator over the keys of D")},
Guido van Rossum59610422002-04-13 14:06:36 +0000749 {"itervalues",(PyCFunction)proxy_itervalues, METH_NOARGS,
Neal Norwitz5dc2a372002-08-13 22:19:13 +0000750 PyDoc_STR("D.itervalues() -> an iterator over the values of D")},
Guido van Rossum59610422002-04-13 14:06:36 +0000751 {"iteritems", (PyCFunction)proxy_iteritems, METH_NOARGS,
Neal Norwitz5dc2a372002-08-13 22:19:13 +0000752 PyDoc_STR("D.iteritems() ->"
753 " an iterator over the (key, value) items of D")},
Guido van Rossum59610422002-04-13 14:06:36 +0000754 {"copy", (PyCFunction)proxy_copy, METH_NOARGS,
Neal Norwitz5dc2a372002-08-13 22:19:13 +0000755 PyDoc_STR("D.copy() -> a shallow copy of D")},
Tim Peters6d6c1a32001-08-02 04:15:00 +0000756 {0}
757};
758
759static void
760proxy_dealloc(proxyobject *pp)
761{
Guido van Rossum048eb752001-10-02 21:24:57 +0000762 _PyObject_GC_UNTRACK(pp);
Tim Peters6d6c1a32001-08-02 04:15:00 +0000763 Py_DECREF(pp->dict);
Guido van Rossum048eb752001-10-02 21:24:57 +0000764 PyObject_GC_Del(pp);
Tim Peters6d6c1a32001-08-02 04:15:00 +0000765}
766
767static PyObject *
768proxy_getiter(proxyobject *pp)
769{
770 return PyObject_GetIter(pp->dict);
771}
772
Neil Schemenauer26775122001-10-21 22:26:43 +0000773static PyObject *
Tim Peters6d6c1a32001-08-02 04:15:00 +0000774proxy_str(proxyobject *pp)
775{
776 return PyObject_Str(pp->dict);
777}
778
Guido van Rossum048eb752001-10-02 21:24:57 +0000779static int
780proxy_traverse(PyObject *self, visitproc visit, void *arg)
781{
782 proxyobject *pp = (proxyobject *)self;
783 int err;
784
785 if (pp->dict) {
786 err = visit(pp->dict, arg);
787 if (err)
788 return err;
789 }
790 return 0;
791}
792
Raymond Hettinger29a6d442002-08-31 15:51:04 +0000793static int
794proxy_compare(proxyobject *v, PyObject *w)
795{
796 return PyObject_Compare(v->dict, w);
797}
798
799static PyObject *
800proxy_richcompare(proxyobject *v, PyObject *w, int op)
801{
802 return PyObject_RichCompare(v->dict, w, op);
803}
804
Neil Schemenauer26775122001-10-21 22:26:43 +0000805static PyTypeObject proxytype = {
Tim Peters6d6c1a32001-08-02 04:15:00 +0000806 PyObject_HEAD_INIT(&PyType_Type)
807 0, /* ob_size */
Guido van Rossumbea18cc2002-06-14 20:41:17 +0000808 "dictproxy", /* tp_name */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000809 sizeof(proxyobject), /* tp_basicsize */
810 0, /* tp_itemsize */
811 /* methods */
812 (destructor)proxy_dealloc, /* tp_dealloc */
813 0, /* tp_print */
814 0, /* tp_getattr */
815 0, /* tp_setattr */
Raymond Hettinger29a6d442002-08-31 15:51:04 +0000816 (cmpfunc)proxy_compare, /* tp_compare */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000817 0, /* tp_repr */
818 0, /* tp_as_number */
819 &proxy_as_sequence, /* tp_as_sequence */
820 &proxy_as_mapping, /* tp_as_mapping */
821 0, /* tp_hash */
822 0, /* tp_call */
823 (reprfunc)proxy_str, /* tp_str */
824 PyObject_GenericGetAttr, /* tp_getattro */
825 0, /* tp_setattro */
826 0, /* tp_as_buffer */
Guido van Rossum048eb752001-10-02 21:24:57 +0000827 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000828 0, /* tp_doc */
Guido van Rossum048eb752001-10-02 21:24:57 +0000829 proxy_traverse, /* tp_traverse */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000830 0, /* tp_clear */
Raymond Hettinger29a6d442002-08-31 15:51:04 +0000831 (richcmpfunc)proxy_richcompare, /* tp_richcompare */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000832 0, /* tp_weaklistoffset */
833 (getiterfunc)proxy_getiter, /* tp_iter */
834 0, /* tp_iternext */
835 proxy_methods, /* tp_methods */
836 0, /* tp_members */
837 0, /* tp_getset */
838 0, /* tp_base */
839 0, /* tp_dict */
840 0, /* tp_descr_get */
841 0, /* tp_descr_set */
842};
843
844PyObject *
845PyDictProxy_New(PyObject *dict)
846{
847 proxyobject *pp;
848
Guido van Rossum048eb752001-10-02 21:24:57 +0000849 pp = PyObject_GC_New(proxyobject, &proxytype);
Tim Peters6d6c1a32001-08-02 04:15:00 +0000850 if (pp != NULL) {
851 Py_INCREF(dict);
852 pp->dict = dict;
Guido van Rossum048eb752001-10-02 21:24:57 +0000853 _PyObject_GC_TRACK(pp);
Tim Peters6d6c1a32001-08-02 04:15:00 +0000854 }
855 return (PyObject *)pp;
856}
857
858
859/* --- Wrapper object for "slot" methods --- */
860
861/* This has no reason to be in this file except that adding new files is a
862 bit of a pain */
863
864typedef struct {
865 PyObject_HEAD
866 PyWrapperDescrObject *descr;
867 PyObject *self;
868} wrapperobject;
869
870static void
871wrapper_dealloc(wrapperobject *wp)
872{
Guido van Rossum048eb752001-10-02 21:24:57 +0000873 _PyObject_GC_UNTRACK(wp);
Tim Peters6d6c1a32001-08-02 04:15:00 +0000874 Py_XDECREF(wp->descr);
875 Py_XDECREF(wp->self);
Guido van Rossum048eb752001-10-02 21:24:57 +0000876 PyObject_GC_Del(wp);
Tim Peters6d6c1a32001-08-02 04:15:00 +0000877}
878
879static PyMethodDef wrapper_methods[] = {
880 {0}
881};
882
883static PyObject *
884wrapper_name(wrapperobject *wp)
885{
886 char *s = wp->descr->d_base->name;
887
888 return PyString_FromString(s);
889}
890
891static PyObject *
892wrapper_doc(wrapperobject *wp)
893{
894 char *s = wp->descr->d_base->doc;
895
896 if (s == NULL) {
897 Py_INCREF(Py_None);
898 return Py_None;
899 }
900 else {
901 return PyString_FromString(s);
902 }
903}
904
Guido van Rossum32d34c82001-09-20 21:45:26 +0000905static PyGetSetDef wrapper_getsets[] = {
Tim Peters6d6c1a32001-08-02 04:15:00 +0000906 {"__name__", (getter)wrapper_name},
907 {"__doc__", (getter)wrapper_doc},
908 {0}
909};
910
911static PyObject *
912wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
913{
914 wrapperfunc wrapper = wp->descr->d_base->wrapper;
915 PyObject *self = wp->self;
916
Guido van Rossumc8e56452001-10-22 00:43:43 +0000917 if (wp->descr->d_base->flags & PyWrapperFlag_KEYWORDS) {
918 wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper;
919 return (*wk)(self, args, wp->descr->d_wrapped, kwds);
920 }
921
922 if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) {
923 PyErr_Format(PyExc_TypeError,
924 "wrapper %s doesn't take keyword arguments",
925 wp->descr->d_base->name);
926 return NULL;
927 }
Tim Peters6d6c1a32001-08-02 04:15:00 +0000928 return (*wrapper)(self, args, wp->descr->d_wrapped);
929}
930
Guido van Rossum048eb752001-10-02 21:24:57 +0000931static int
932wrapper_traverse(PyObject *self, visitproc visit, void *arg)
933{
934 wrapperobject *wp = (wrapperobject *)self;
935 int err;
936
937 if (wp->descr) {
938 err = visit((PyObject *)(wp->descr), arg);
939 if (err)
940 return err;
941 }
942 if (wp->self) {
943 err = visit(wp->self, arg);
944 if (err)
945 return err;
946 }
947 return 0;
948}
949
Neil Schemenauer26775122001-10-21 22:26:43 +0000950static PyTypeObject wrappertype = {
Tim Peters6d6c1a32001-08-02 04:15:00 +0000951 PyObject_HEAD_INIT(&PyType_Type)
952 0, /* ob_size */
953 "method-wrapper", /* tp_name */
954 sizeof(wrapperobject), /* tp_basicsize */
955 0, /* tp_itemsize */
956 /* methods */
957 (destructor)wrapper_dealloc, /* tp_dealloc */
958 0, /* tp_print */
959 0, /* tp_getattr */
960 0, /* tp_setattr */
961 0, /* tp_compare */
962 0, /* tp_repr */
963 0, /* tp_as_number */
964 0, /* tp_as_sequence */
965 0, /* tp_as_mapping */
966 0, /* tp_hash */
967 (ternaryfunc)wrapper_call, /* tp_call */
968 0, /* tp_str */
969 PyObject_GenericGetAttr, /* tp_getattro */
970 0, /* tp_setattro */
971 0, /* tp_as_buffer */
Guido van Rossum048eb752001-10-02 21:24:57 +0000972 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000973 0, /* tp_doc */
Guido van Rossum048eb752001-10-02 21:24:57 +0000974 wrapper_traverse, /* tp_traverse */
Tim Peters6d6c1a32001-08-02 04:15:00 +0000975 0, /* tp_clear */
976 0, /* tp_richcompare */
977 0, /* tp_weaklistoffset */
978 0, /* tp_iter */
979 0, /* tp_iternext */
980 wrapper_methods, /* tp_methods */
981 0, /* tp_members */
982 wrapper_getsets, /* tp_getset */
983 0, /* tp_base */
984 0, /* tp_dict */
985 0, /* tp_descr_get */
986 0, /* tp_descr_set */
987};
988
989PyObject *
990PyWrapper_New(PyObject *d, PyObject *self)
991{
992 wrapperobject *wp;
993 PyWrapperDescrObject *descr;
994
995 assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));
996 descr = (PyWrapperDescrObject *)d;
997 assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type)));
998
Guido van Rossum048eb752001-10-02 21:24:57 +0000999 wp = PyObject_GC_New(wrapperobject, &wrappertype);
Tim Peters6d6c1a32001-08-02 04:15:00 +00001000 if (wp != NULL) {
1001 Py_INCREF(descr);
1002 wp->descr = descr;
1003 Py_INCREF(self);
1004 wp->self = self;
Guido van Rossum048eb752001-10-02 21:24:57 +00001005 _PyObject_GC_TRACK(wp);
Tim Peters6d6c1a32001-08-02 04:15:00 +00001006 }
1007 return (PyObject *)wp;
1008}
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001009
1010
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001011/* A built-in 'property' type */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001012
1013/*
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001014 class property(object):
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001015
Guido van Rossumba2485f2001-12-10 18:03:34 +00001016 def __init__(self, fget=None, fset=None, fdel=None, doc=None):
1017 self.__get = fget
1018 self.__set = fset
1019 self.__del = fdel
1020 self.__doc__ = doc
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001021
Guido van Rossumba2485f2001-12-10 18:03:34 +00001022 def __get__(self, inst, type=None):
Guido van Rossumba2485f2001-12-10 18:03:34 +00001023 if inst is None:
1024 return self
Guido van Rossum7171f1c2001-12-10 18:06:21 +00001025 if self.__get is None:
1026 raise AttributeError, "unreadable attribute"
Guido van Rossumba2485f2001-12-10 18:03:34 +00001027 return self.__get(inst)
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001028
Guido van Rossumba2485f2001-12-10 18:03:34 +00001029 def __set__(self, inst, value):
1030 if self.__set is None:
1031 raise AttributeError, "can't set attribute"
1032 return self.__set(inst, value)
1033
1034 def __delete__(self, inst):
1035 if self.__del is None:
1036 raise AttributeError, "can't delete attribute"
1037 return self.__del(inst)
1038
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001039*/
1040
1041typedef struct {
1042 PyObject_HEAD
Tim Peters66c1a522001-09-24 21:17:50 +00001043 PyObject *prop_get;
1044 PyObject *prop_set;
1045 PyObject *prop_del;
1046 PyObject *prop_doc;
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001047} propertyobject;
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001048
Tim Peters66c1a522001-09-24 21:17:50 +00001049static PyMemberDef property_members[] = {
1050 {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY},
1051 {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY},
1052 {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY},
1053 {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY},
1054 {0}
1055};
1056
1057
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001058static void
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001059property_dealloc(PyObject *self)
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001060{
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001061 propertyobject *gs = (propertyobject *)self;
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001062
Guido van Rossum048eb752001-10-02 21:24:57 +00001063 _PyObject_GC_UNTRACK(self);
Tim Peters66c1a522001-09-24 21:17:50 +00001064 Py_XDECREF(gs->prop_get);
1065 Py_XDECREF(gs->prop_set);
1066 Py_XDECREF(gs->prop_del);
1067 Py_XDECREF(gs->prop_doc);
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001068 self->ob_type->tp_free(self);
1069}
1070
1071static PyObject *
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001072property_descr_get(PyObject *self, PyObject *obj, PyObject *type)
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001073{
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001074 propertyobject *gs = (propertyobject *)self;
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001075
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001076 if (obj == NULL || obj == Py_None) {
1077 Py_INCREF(self);
1078 return self;
1079 }
Guido van Rossumb75ba912001-12-10 18:00:15 +00001080 if (gs->prop_get == NULL) {
1081 PyErr_SetString(PyExc_AttributeError, "unreadable attribute");
1082 return NULL;
1083 }
Tim Peters66c1a522001-09-24 21:17:50 +00001084 return PyObject_CallFunction(gs->prop_get, "(O)", obj);
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001085}
1086
1087static int
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001088property_descr_set(PyObject *self, PyObject *obj, PyObject *value)
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001089{
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001090 propertyobject *gs = (propertyobject *)self;
Guido van Rossum271410a2001-08-24 15:23:20 +00001091 PyObject *func, *res;
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001092
Guido van Rossum271410a2001-08-24 15:23:20 +00001093 if (value == NULL)
Tim Peters66c1a522001-09-24 21:17:50 +00001094 func = gs->prop_del;
Guido van Rossum271410a2001-08-24 15:23:20 +00001095 else
Tim Peters66c1a522001-09-24 21:17:50 +00001096 func = gs->prop_set;
Guido van Rossum271410a2001-08-24 15:23:20 +00001097 if (func == NULL) {
1098 PyErr_SetString(PyExc_AttributeError,
1099 value == NULL ?
1100 "can't delete attribute" :
1101 "can't set attribute");
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001102 return -1;
1103 }
Guido van Rossum845fc482001-08-24 10:17:36 +00001104 if (value == NULL)
Guido van Rossum271410a2001-08-24 15:23:20 +00001105 res = PyObject_CallFunction(func, "(O)", obj);
Guido van Rossum845fc482001-08-24 10:17:36 +00001106 else
Guido van Rossum271410a2001-08-24 15:23:20 +00001107 res = PyObject_CallFunction(func, "(OO)", obj, value);
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001108 if (res == NULL)
1109 return -1;
1110 Py_DECREF(res);
1111 return 0;
1112}
1113
1114static int
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001115property_init(PyObject *self, PyObject *args, PyObject *kwds)
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001116{
Tim Peters66c1a522001-09-24 21:17:50 +00001117 PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL;
1118 static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0};
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001119 propertyobject *gs = (propertyobject *)self;
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001120
Tim Peters66c1a522001-09-24 21:17:50 +00001121 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property",
1122 kwlist, &get, &set, &del, &doc))
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001123 return -1;
Tim Peters66c1a522001-09-24 21:17:50 +00001124
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001125 if (get == Py_None)
1126 get = NULL;
1127 if (set == Py_None)
1128 set = NULL;
Tim Peters66c1a522001-09-24 21:17:50 +00001129 if (del == Py_None)
1130 del = NULL;
1131
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001132 Py_XINCREF(get);
1133 Py_XINCREF(set);
Guido van Rossum271410a2001-08-24 15:23:20 +00001134 Py_XINCREF(del);
Tim Peters66c1a522001-09-24 21:17:50 +00001135 Py_XINCREF(doc);
1136
1137 gs->prop_get = get;
1138 gs->prop_set = set;
1139 gs->prop_del = del;
1140 gs->prop_doc = doc;
1141
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001142 return 0;
1143}
1144
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001145PyDoc_STRVAR(property_doc,
Tim Peters66c1a522001-09-24 21:17:50 +00001146"property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n"
1147"\n"
1148"fget is a function to be used for getting an attribute value, and likewise\n"
1149"fset is a function for setting, and fdel a function for del'ing, an\n"
1150"attribute. Typical use is to define a managed attribute x:\n"
Guido van Rossum91c0d8a2001-08-24 09:55:51 +00001151"class C(object):\n"
1152" def getx(self): return self.__x\n"
1153" def setx(self, value): self.__x = value\n"
Guido van Rossum271410a2001-08-24 15:23:20 +00001154" def delx(self): del self.__x\n"
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +00001155" x = property(getx, setx, delx, \"I'm the 'x' property.\")");
Guido van Rossum91c0d8a2001-08-24 09:55:51 +00001156
Guido van Rossum048eb752001-10-02 21:24:57 +00001157static int
1158property_traverse(PyObject *self, visitproc visit, void *arg)
1159{
1160 propertyobject *pp = (propertyobject *)self;
1161 int err;
1162
1163#define VISIT(SLOT) \
1164 if (pp->SLOT) { \
1165 err = visit((PyObject *)(pp->SLOT), arg); \
1166 if (err) \
1167 return err; \
1168 }
1169
1170 VISIT(prop_get);
1171 VISIT(prop_set);
1172 VISIT(prop_del);
1173
1174 return 0;
1175}
1176
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001177PyTypeObject PyProperty_Type = {
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001178 PyObject_HEAD_INIT(&PyType_Type)
1179 0, /* ob_size */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001180 "property", /* tp_name */
1181 sizeof(propertyobject), /* tp_basicsize */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001182 0, /* tp_itemsize */
1183 /* methods */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001184 property_dealloc, /* tp_dealloc */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001185 0, /* tp_print */
1186 0, /* tp_getattr */
1187 0, /* tp_setattr */
1188 0, /* tp_compare */
1189 0, /* tp_repr */
1190 0, /* tp_as_number */
1191 0, /* tp_as_sequence */
1192 0, /* tp_as_mapping */
1193 0, /* tp_hash */
1194 0, /* tp_call */
1195 0, /* tp_str */
1196 PyObject_GenericGetAttr, /* tp_getattro */
1197 0, /* tp_setattro */
1198 0, /* tp_as_buffer */
Guido van Rossum048eb752001-10-02 21:24:57 +00001199 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1200 Py_TPFLAGS_BASETYPE, /* tp_flags */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001201 property_doc, /* tp_doc */
Guido van Rossum048eb752001-10-02 21:24:57 +00001202 property_traverse, /* tp_traverse */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001203 0, /* tp_clear */
1204 0, /* tp_richcompare */
1205 0, /* tp_weaklistoffset */
1206 0, /* tp_iter */
1207 0, /* tp_iternext */
1208 0, /* tp_methods */
Tim Peters66c1a522001-09-24 21:17:50 +00001209 property_members, /* tp_members */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001210 0, /* tp_getset */
1211 0, /* tp_base */
1212 0, /* tp_dict */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001213 property_descr_get, /* tp_descr_get */
1214 property_descr_set, /* tp_descr_set */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001215 0, /* tp_dictoffset */
Guido van Rossum8bce4ac2001-09-06 21:56:42 +00001216 property_init, /* tp_init */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001217 PyType_GenericAlloc, /* tp_alloc */
1218 PyType_GenericNew, /* tp_new */
Neil Schemenauer99b5d282002-04-12 02:44:22 +00001219 PyObject_GC_Del, /* tp_free */
Guido van Rossum29a62dd2001-08-23 21:40:38 +00001220};