blob: 40629f6c24ae16327ecf7e6b012c62805682bba8 [file] [log] [blame]
Tim Peters6d6c1a32001-08-02 04:15:00 +00001/* Descriptors -- a new, flexible way to describe attributes */
2
3#include "Python.h"
4#include "structmember.h" /* Why is this not included in Python.h? */
5
6/* Various kinds of descriptor objects */
7
8#define COMMON \
9 PyObject_HEAD \
10 PyTypeObject *d_type; \
11 PyObject *d_name
12
13typedef struct {
14 COMMON;
15} PyDescrObject;
16
17typedef struct {
18 COMMON;
19 PyMethodDef *d_method;
20} PyMethodDescrObject;
21
22typedef struct {
23 COMMON;
24 struct memberlist *d_member;
25} PyMemberDescrObject;
26
27typedef struct {
28 COMMON;
29 struct getsetlist *d_getset;
30} PyGetSetDescrObject;
31
32typedef struct {
33 COMMON;
34 struct wrapperbase *d_base;
35 void *d_wrapped; /* This can be any function pointer */
36} PyWrapperDescrObject;
37
38static void
39descr_dealloc(PyDescrObject *descr)
40{
41 Py_XDECREF(descr->d_type);
42 Py_XDECREF(descr->d_name);
43 PyObject_DEL(descr);
44}
45
46static char *
47descr_name(PyDescrObject *descr)
48{
49 if (descr->d_name != NULL && PyString_Check(descr->d_name))
50 return PyString_AS_STRING(descr->d_name);
51 else
52 return "?";
53}
54
55static PyObject *
56descr_repr(PyDescrObject *descr, char *format)
57{
58 char buffer[500];
59
60 sprintf(buffer, format, descr_name(descr), descr->d_type->tp_name);
61 return PyString_FromString(buffer);
62}
63
64static PyObject *
65method_repr(PyMethodDescrObject *descr)
66{
67 return descr_repr((PyDescrObject *)descr,
68 "<method '%.300s' of '%.100s' objects>");
69}
70
71static PyObject *
72member_repr(PyMemberDescrObject *descr)
73{
74 return descr_repr((PyDescrObject *)descr,
75 "<member '%.300s' of '%.100s' objects>");
76}
77
78static PyObject *
79getset_repr(PyGetSetDescrObject *descr)
80{
81 return descr_repr((PyDescrObject *)descr,
82 "<attribute '%.300s' of '%.100s' objects>");
83}
84
85static PyObject *
86wrapper_repr(PyWrapperDescrObject *descr)
87{
88 return descr_repr((PyDescrObject *)descr,
89 "<slot wrapper '%.300s' of '%.100s' objects>");
90}
91
92static int
93descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
94 PyObject **pres)
95{
96 if (obj == NULL || obj == Py_None) {
97 Py_INCREF(descr);
98 *pres = (PyObject *)descr;
99 return 1;
100 }
101 if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
102 PyErr_Format(PyExc_TypeError,
103 "descriptor '%.200s' for '%.100s' objects "
104 "doesn't apply to '%.100s' object",
105 descr_name((PyDescrObject *)descr),
106 descr->d_type->tp_name,
107 obj->ob_type->tp_name);
108 *pres = NULL;
109 return 1;
110 }
111 return 0;
112}
113
114static PyObject *
115method_get(PyMethodDescrObject *descr, PyObject *obj, PyTypeObject *type)
116{
117 PyObject *res;
118
119 if (descr_check((PyDescrObject *)descr, obj, type, &res))
120 return res;
121 return PyCFunction_New(descr->d_method, obj);
122}
123
124static PyObject *
125member_get(PyMemberDescrObject *descr, PyObject *obj, PyTypeObject *type)
126{
127 PyObject *res;
128
129 if (descr_check((PyDescrObject *)descr, obj, type, &res))
130 return res;
131 return PyMember_Get((char *)obj, descr->d_member,
132 descr->d_member->name);
133}
134
135static PyObject *
136getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
137{
138 PyObject *res;
139
140 if (descr_check((PyDescrObject *)descr, obj, type, &res))
141 return res;
142 if (descr->d_getset->get != NULL)
143 return descr->d_getset->get(obj, descr->d_getset->closure);
144 PyErr_Format(PyExc_TypeError,
145 "attribute '%300s' of '%.100s' objects is not readable",
146 descr_name((PyDescrObject *)descr),
147 descr->d_type->tp_name);
148 return NULL;
149}
150
151static PyObject *
152wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyTypeObject *type)
153{
154 PyObject *res;
155
156 if (descr_check((PyDescrObject *)descr, obj, type, &res))
157 return res;
158 return PyWrapper_New((PyObject *)descr, obj);
159}
160
161static int
162descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,
163 int *pres)
164{
165 assert(obj != NULL);
166 if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) {
167 PyErr_Format(PyExc_TypeError,
168 "descriptor '%.200s' for '%.100s' objects "
169 "doesn't apply to '%.100s' object",
170 descr_name(descr),
171 descr->d_type->tp_name,
172 obj->ob_type->tp_name);
173 *pres = -1;
174 return 1;
175 }
176 return 0;
177}
178
179static int
180member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)
181{
182 int res;
183
184 if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
185 return res;
186 return PyMember_Set((char *)obj, descr->d_member,
187 descr->d_member->name, value);
188}
189
190static int
191getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
192{
193 int res;
194
195 if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))
196 return res;
197 if (descr->d_getset->set != NULL)
198 return descr->d_getset->set(obj, value,
199 descr->d_getset->closure);
200 PyErr_Format(PyExc_TypeError,
201 "attribute '%300s' of '%.100s' objects is not writable",
202 descr_name((PyDescrObject *)descr),
203 descr->d_type->tp_name);
204 return -1;
205}
206
207static PyObject *
208methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)
209{
210 int argc;
211 PyObject *self, *func, *result;
212
213 /* Make sure that the first argument is acceptable as 'self' */
214 assert(PyTuple_Check(args));
215 argc = PyTuple_GET_SIZE(args);
216 if (argc < 1) {
217 PyErr_Format(PyExc_TypeError,
218 "descriptor '%.300s' of '%.100s' "
219 "object needs an argument",
220 descr_name((PyDescrObject *)descr),
221 descr->d_type->tp_name);
222 return NULL;
223 }
224 self = PyTuple_GET_ITEM(args, 0);
225 if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
226 PyErr_Format(PyExc_TypeError,
227 "descriptor '%.200s' "
228 "requires a '%.100s' object "
229 "but received a '%.100s'",
230 descr_name((PyDescrObject *)descr),
231 descr->d_type->tp_name,
232 self->ob_type->tp_name);
233 return NULL;
234 }
235
236 func = PyCFunction_New(descr->d_method, self);
237 if (func == NULL)
238 return NULL;
239 args = PyTuple_GetSlice(args, 1, argc);
240 if (args == NULL) {
241 Py_DECREF(func);
242 return NULL;
243 }
244 result = PyEval_CallObjectWithKeywords(func, args, kwds);
245 Py_DECREF(args);
246 Py_DECREF(func);
247 return result;
248}
249
250static PyObject *
251wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)
252{
253 int argc;
254 PyObject *self, *func, *result;
255
256 /* Make sure that the first argument is acceptable as 'self' */
257 assert(PyTuple_Check(args));
258 argc = PyTuple_GET_SIZE(args);
259 if (argc < 1) {
260 PyErr_Format(PyExc_TypeError,
261 "descriptor '%.300s' of '%.100s' "
262 "object needs an argument",
263 descr_name((PyDescrObject *)descr),
264 descr->d_type->tp_name);
265 return NULL;
266 }
267 self = PyTuple_GET_ITEM(args, 0);
268 if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) {
269 PyErr_Format(PyExc_TypeError,
270 "descriptor '%.200s' "
271 "requires a '%.100s' object "
272 "but received a '%.100s'",
273 descr_name((PyDescrObject *)descr),
274 descr->d_type->tp_name,
275 self->ob_type->tp_name);
276 return NULL;
277 }
278
279 func = PyWrapper_New((PyObject *)descr, self);
280 if (func == NULL)
281 return NULL;
282 args = PyTuple_GetSlice(args, 1, argc);
283 if (args == NULL) {
284 Py_DECREF(func);
285 return NULL;
286 }
287 result = PyEval_CallObjectWithKeywords(func, args, kwds);
288 Py_DECREF(args);
289 Py_DECREF(func);
290 return result;
291}
292
293static PyObject *
294member_get_doc(PyMethodDescrObject *descr, void *closure)
295{
296 if (descr->d_method->ml_doc == NULL) {
297 Py_INCREF(Py_None);
298 return Py_None;
299 }
300 return PyString_FromString(descr->d_method->ml_doc);
301}
302
303static struct memberlist descr_members[] = {
304 {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},
305 {"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},
306 {0}
307};
308
309static struct getsetlist member_getset[] = {
310 {"__doc__", (getter)member_get_doc},
311 {0}
312};
313
314static PyObject *
315wrapper_get_doc(PyWrapperDescrObject *descr, void *closure)
316{
317 if (descr->d_base->doc == NULL) {
318 Py_INCREF(Py_None);
319 return Py_None;
320 }
321 return PyString_FromString(descr->d_base->doc);
322}
323
324static struct getsetlist wrapper_getset[] = {
325 {"__doc__", (getter)wrapper_get_doc},
326 {0}
327};
328
329static PyTypeObject PyMethodDescr_Type = {
330 PyObject_HEAD_INIT(&PyType_Type)
331 0,
332 "method_descriptor",
333 sizeof(PyMethodDescrObject),
334 0,
335 (destructor)descr_dealloc, /* tp_dealloc */
336 0, /* tp_print */
337 0, /* tp_getattr */
338 0, /* tp_setattr */
339 0, /* tp_compare */
340 (reprfunc)method_repr, /* tp_repr */
341 0, /* tp_as_number */
342 0, /* tp_as_sequence */
343 0, /* tp_as_mapping */
344 0, /* tp_hash */
345 (ternaryfunc)methoddescr_call, /* tp_call */
346 0, /* tp_str */
347 PyObject_GenericGetAttr, /* tp_getattro */
348 0, /* tp_setattro */
349 0, /* tp_as_buffer */
350 Py_TPFLAGS_DEFAULT, /* tp_flags */
351 0, /* tp_doc */
352 0, /* tp_traverse */
353 0, /* tp_clear */
354 0, /* tp_richcompare */
355 0, /* tp_weaklistoffset */
356 0, /* tp_iter */
357 0, /* tp_iternext */
358 0, /* tp_methods */
359 descr_members, /* tp_members */
360 member_getset, /* tp_getset */
361 0, /* tp_base */
362 0, /* tp_dict */
363 (descrgetfunc)method_get, /* tp_descr_get */
364 0, /* tp_descr_set */
365};
366
367static PyTypeObject PyMemberDescr_Type = {
368 PyObject_HEAD_INIT(&PyType_Type)
369 0,
370 "member_descriptor",
371 sizeof(PyMemberDescrObject),
372 0,
373 (destructor)descr_dealloc, /* tp_dealloc */
374 0, /* tp_print */
375 0, /* tp_getattr */
376 0, /* tp_setattr */
377 0, /* tp_compare */
378 (reprfunc)member_repr, /* tp_repr */
379 0, /* tp_as_number */
380 0, /* tp_as_sequence */
381 0, /* tp_as_mapping */
382 0, /* tp_hash */
383 (ternaryfunc)0, /* tp_call */
384 0, /* tp_str */
385 PyObject_GenericGetAttr, /* tp_getattro */
386 0, /* tp_setattro */
387 0, /* tp_as_buffer */
388 Py_TPFLAGS_DEFAULT, /* tp_flags */
389 0, /* tp_doc */
390 0, /* tp_traverse */
391 0, /* tp_clear */
392 0, /* tp_richcompare */
393 0, /* tp_weaklistoffset */
394 0, /* tp_iter */
395 0, /* tp_iternext */
396 0, /* tp_methods */
397 descr_members, /* tp_members */
398 0, /* tp_getset */
399 0, /* tp_base */
400 0, /* tp_dict */
401 (descrgetfunc)member_get, /* tp_descr_get */
402 (descrsetfunc)member_set, /* tp_descr_set */
403};
404
405static PyTypeObject PyGetSetDescr_Type = {
406 PyObject_HEAD_INIT(&PyType_Type)
407 0,
408 "getset_descriptor",
409 sizeof(PyGetSetDescrObject),
410 0,
411 (destructor)descr_dealloc, /* tp_dealloc */
412 0, /* tp_print */
413 0, /* tp_getattr */
414 0, /* tp_setattr */
415 0, /* tp_compare */
416 (reprfunc)getset_repr, /* tp_repr */
417 0, /* tp_as_number */
418 0, /* tp_as_sequence */
419 0, /* tp_as_mapping */
420 0, /* tp_hash */
421 (ternaryfunc)0, /* tp_call */
422 0, /* tp_str */
423 PyObject_GenericGetAttr, /* tp_getattro */
424 0, /* tp_setattro */
425 0, /* tp_as_buffer */
426 Py_TPFLAGS_DEFAULT, /* tp_flags */
427 0, /* tp_doc */
428 0, /* tp_traverse */
429 0, /* tp_clear */
430 0, /* tp_richcompare */
431 0, /* tp_weaklistoffset */
432 0, /* tp_iter */
433 0, /* tp_iternext */
434 0, /* tp_methods */
435 descr_members, /* tp_members */
436 0, /* tp_getset */
437 0, /* tp_base */
438 0, /* tp_dict */
439 (descrgetfunc)getset_get, /* tp_descr_get */
440 (descrsetfunc)getset_set, /* tp_descr_set */
441};
442
443static PyTypeObject PyWrapperDescr_Type = {
444 PyObject_HEAD_INIT(&PyType_Type)
445 0,
446 "wrapper_descriptor",
447 sizeof(PyWrapperDescrObject),
448 0,
449 (destructor)descr_dealloc, /* tp_dealloc */
450 0, /* tp_print */
451 0, /* tp_getattr */
452 0, /* tp_setattr */
453 0, /* tp_compare */
454 (reprfunc)wrapper_repr, /* tp_repr */
455 0, /* tp_as_number */
456 0, /* tp_as_sequence */
457 0, /* tp_as_mapping */
458 0, /* tp_hash */
459 (ternaryfunc)wrapperdescr_call, /* tp_call */
460 0, /* tp_str */
461 PyObject_GenericGetAttr, /* tp_getattro */
462 0, /* tp_setattro */
463 0, /* tp_as_buffer */
464 Py_TPFLAGS_DEFAULT, /* tp_flags */
465 0, /* tp_doc */
466 0, /* tp_traverse */
467 0, /* tp_clear */
468 0, /* tp_richcompare */
469 0, /* tp_weaklistoffset */
470 0, /* tp_iter */
471 0, /* tp_iternext */
472 0, /* tp_methods */
473 descr_members, /* tp_members */
474 wrapper_getset, /* tp_getset */
475 0, /* tp_base */
476 0, /* tp_dict */
477 (descrgetfunc)wrapper_get, /* tp_descr_get */
478 0, /* tp_descr_set */
479};
480
481static PyDescrObject *
482descr_new(PyTypeObject *descrtype, PyTypeObject *type, char *name)
483{
484 PyDescrObject *descr;
485
486 descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);
487 if (descr != NULL) {
488 Py_XINCREF(type);
489 descr->d_type = type;
490 descr->d_name = PyString_InternFromString(name);
491 if (descr->d_name == NULL) {
492 Py_DECREF(descr);
493 descr = NULL;
494 }
495 }
496 return descr;
497}
498
499PyObject *
500PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
501{
502 PyMethodDescrObject *descr;
503
504 descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
505 type, method->ml_name);
506 if (descr != NULL)
507 descr->d_method = method;
508 return (PyObject *)descr;
509}
510
511PyObject *
512PyDescr_NewMember(PyTypeObject *type, struct memberlist *member)
513{
514 PyMemberDescrObject *descr;
515
516 descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,
517 type, member->name);
518 if (descr != NULL)
519 descr->d_member = member;
520 return (PyObject *)descr;
521}
522
523PyObject *
524PyDescr_NewGetSet(PyTypeObject *type, struct getsetlist *getset)
525{
526 PyGetSetDescrObject *descr;
527
528 descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
529 type, getset->name);
530 if (descr != NULL)
531 descr->d_getset = getset;
532 return (PyObject *)descr;
533}
534
535PyObject *
536PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
537{
538 PyWrapperDescrObject *descr;
539
540 descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
541 type, base->name);
542 if (descr != NULL) {
543 descr->d_base = base;
544 descr->d_wrapped = wrapped;
545 }
546 return (PyObject *)descr;
547}
548
549int
550PyDescr_IsData(PyObject *d)
551{
552 return d->ob_type->tp_descr_set != NULL;
553}
554
555
556/* --- Readonly proxy for dictionaries (actually any mapping) --- */
557
558/* This has no reason to be in this file except that adding new files is a
559 bit of a pain */
560
561typedef struct {
562 PyObject_HEAD
563 PyObject *dict;
564} proxyobject;
565
566static int
567proxy_len(proxyobject *pp)
568{
569 return PyObject_Size(pp->dict);
570}
571
572static PyObject *
573proxy_getitem(proxyobject *pp, PyObject *key)
574{
575 return PyObject_GetItem(pp->dict, key);
576}
577
578static PyMappingMethods proxy_as_mapping = {
579 (inquiry)proxy_len, /* mp_length */
580 (binaryfunc)proxy_getitem, /* mp_subscript */
581 0, /* mp_ass_subscript */
582};
583
584static int
585proxy_contains(proxyobject *pp, PyObject *key)
586{
587 return PySequence_Contains(pp->dict, key);
588}
589
590static PySequenceMethods proxy_as_sequence = {
591 0, /* sq_length */
592 0, /* sq_concat */
593 0, /* sq_repeat */
594 0, /* sq_item */
595 0, /* sq_slice */
596 0, /* sq_ass_item */
597 0, /* sq_ass_slice */
598 (objobjproc)proxy_contains, /* sq_contains */
599 0, /* sq_inplace_concat */
600 0, /* sq_inplace_repeat */
601};
602
603static PyObject *
604proxy_has_key(proxyobject *pp, PyObject *args)
605{
606 PyObject *key;
607
608 if (!PyArg_ParseTuple(args, "O:has_key", &key))
609 return NULL;
610 return PyInt_FromLong(PySequence_Contains(pp->dict, key));
611}
612
613static PyObject *
614proxy_get(proxyobject *pp, PyObject *args)
615{
616 PyObject *key, *def = Py_None;
617
618 if (!PyArg_ParseTuple(args, "O|O:get", &key, &def))
619 return NULL;
620 return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);
621}
622
623static PyObject *
624proxy_keys(proxyobject *pp, PyObject *args)
625{
626 if (!PyArg_ParseTuple(args, ":keys"))
627 return NULL;
628 return PyMapping_Keys(pp->dict);
629}
630
631static PyObject *
632proxy_values(proxyobject *pp, PyObject *args)
633{
634 if (!PyArg_ParseTuple(args, ":values"))
635 return NULL;
636 return PyMapping_Values(pp->dict);
637}
638
639static PyObject *
640proxy_items(proxyobject *pp, PyObject *args)
641{
642 if (!PyArg_ParseTuple(args, ":items"))
643 return NULL;
644 return PyMapping_Items(pp->dict);
645}
646
647static PyObject *
648proxy_copy(proxyobject *pp, PyObject *args)
649{
650 if (!PyArg_ParseTuple(args, ":copy"))
651 return NULL;
652 return PyObject_CallMethod(pp->dict, "copy", NULL);
653}
654
655static PyMethodDef proxy_methods[] = {
656 {"has_key", (PyCFunction)proxy_has_key, METH_VARARGS, "XXX"},
657 {"get", (PyCFunction)proxy_get, METH_VARARGS, "XXX"},
658 {"keys", (PyCFunction)proxy_keys, METH_VARARGS, "XXX"},
659 {"values", (PyCFunction)proxy_values, METH_VARARGS, "XXX"},
660 {"items", (PyCFunction)proxy_items, METH_VARARGS, "XXX"},
661 {"copy", (PyCFunction)proxy_copy, METH_VARARGS, "XXX"},
662 {0}
663};
664
665static void
666proxy_dealloc(proxyobject *pp)
667{
668 Py_DECREF(pp->dict);
669 PyObject_DEL(pp);
670}
671
672static PyObject *
673proxy_getiter(proxyobject *pp)
674{
675 return PyObject_GetIter(pp->dict);
676}
677
678PyObject *
679proxy_str(proxyobject *pp)
680{
681 return PyObject_Str(pp->dict);
682}
683
684PyTypeObject proxytype = {
685 PyObject_HEAD_INIT(&PyType_Type)
686 0, /* ob_size */
687 "dict-proxy", /* tp_name */
688 sizeof(proxyobject), /* tp_basicsize */
689 0, /* tp_itemsize */
690 /* methods */
691 (destructor)proxy_dealloc, /* tp_dealloc */
692 0, /* tp_print */
693 0, /* tp_getattr */
694 0, /* tp_setattr */
695 0, /* tp_compare */
696 0, /* tp_repr */
697 0, /* tp_as_number */
698 &proxy_as_sequence, /* tp_as_sequence */
699 &proxy_as_mapping, /* tp_as_mapping */
700 0, /* tp_hash */
701 0, /* tp_call */
702 (reprfunc)proxy_str, /* tp_str */
703 PyObject_GenericGetAttr, /* tp_getattro */
704 0, /* tp_setattro */
705 0, /* tp_as_buffer */
706 Py_TPFLAGS_DEFAULT, /* tp_flags */
707 0, /* tp_doc */
708 0, /* tp_traverse */
709 0, /* tp_clear */
710 0, /* tp_richcompare */
711 0, /* tp_weaklistoffset */
712 (getiterfunc)proxy_getiter, /* tp_iter */
713 0, /* tp_iternext */
714 proxy_methods, /* tp_methods */
715 0, /* tp_members */
716 0, /* tp_getset */
717 0, /* tp_base */
718 0, /* tp_dict */
719 0, /* tp_descr_get */
720 0, /* tp_descr_set */
721};
722
723PyObject *
724PyDictProxy_New(PyObject *dict)
725{
726 proxyobject *pp;
727
728 pp = PyObject_NEW(proxyobject, &proxytype);
729 if (pp != NULL) {
730 Py_INCREF(dict);
731 pp->dict = dict;
732 }
733 return (PyObject *)pp;
734}
735
736
737/* --- Wrapper object for "slot" methods --- */
738
739/* This has no reason to be in this file except that adding new files is a
740 bit of a pain */
741
742typedef struct {
743 PyObject_HEAD
744 PyWrapperDescrObject *descr;
745 PyObject *self;
746} wrapperobject;
747
748static void
749wrapper_dealloc(wrapperobject *wp)
750{
751 Py_XDECREF(wp->descr);
752 Py_XDECREF(wp->self);
753 PyObject_DEL(wp);
754}
755
756static PyMethodDef wrapper_methods[] = {
757 {0}
758};
759
760static PyObject *
761wrapper_name(wrapperobject *wp)
762{
763 char *s = wp->descr->d_base->name;
764
765 return PyString_FromString(s);
766}
767
768static PyObject *
769wrapper_doc(wrapperobject *wp)
770{
771 char *s = wp->descr->d_base->doc;
772
773 if (s == NULL) {
774 Py_INCREF(Py_None);
775 return Py_None;
776 }
777 else {
778 return PyString_FromString(s);
779 }
780}
781
782static struct getsetlist wrapper_getsets[] = {
783 {"__name__", (getter)wrapper_name},
784 {"__doc__", (getter)wrapper_doc},
785 {0}
786};
787
788static PyObject *
789wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
790{
791 wrapperfunc wrapper = wp->descr->d_base->wrapper;
792 PyObject *self = wp->self;
793
794 return (*wrapper)(self, args, wp->descr->d_wrapped);
795}
796
797PyTypeObject wrappertype = {
798 PyObject_HEAD_INIT(&PyType_Type)
799 0, /* ob_size */
800 "method-wrapper", /* tp_name */
801 sizeof(wrapperobject), /* tp_basicsize */
802 0, /* tp_itemsize */
803 /* methods */
804 (destructor)wrapper_dealloc, /* tp_dealloc */
805 0, /* tp_print */
806 0, /* tp_getattr */
807 0, /* tp_setattr */
808 0, /* tp_compare */
809 0, /* tp_repr */
810 0, /* tp_as_number */
811 0, /* tp_as_sequence */
812 0, /* tp_as_mapping */
813 0, /* tp_hash */
814 (ternaryfunc)wrapper_call, /* tp_call */
815 0, /* tp_str */
816 PyObject_GenericGetAttr, /* tp_getattro */
817 0, /* tp_setattro */
818 0, /* tp_as_buffer */
819 Py_TPFLAGS_DEFAULT, /* tp_flags */
820 0, /* tp_doc */
821 0, /* tp_traverse */
822 0, /* tp_clear */
823 0, /* tp_richcompare */
824 0, /* tp_weaklistoffset */
825 0, /* tp_iter */
826 0, /* tp_iternext */
827 wrapper_methods, /* tp_methods */
828 0, /* tp_members */
829 wrapper_getsets, /* tp_getset */
830 0, /* tp_base */
831 0, /* tp_dict */
832 0, /* tp_descr_get */
833 0, /* tp_descr_set */
834};
835
836PyObject *
837PyWrapper_New(PyObject *d, PyObject *self)
838{
839 wrapperobject *wp;
840 PyWrapperDescrObject *descr;
841
842 assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));
843 descr = (PyWrapperDescrObject *)d;
844 assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type)));
845
846 wp = PyObject_NEW(wrapperobject, &wrappertype);
847 if (wp != NULL) {
848 Py_INCREF(descr);
849 wp->descr = descr;
850 Py_INCREF(self);
851 wp->self = self;
852 }
853 return (PyObject *)wp;
854}