]>
Commit | Line | Data |
---|---|---|
53b2ba57 DM |
1 | /* Descriptors -- a new, flexible way to describe attributes */\r |
2 | \r | |
3 | #include "Python.h"\r | |
4 | #include "structmember.h" /* Why is this not included in Python.h? */\r | |
5 | \r | |
6 | static void\r | |
7 | descr_dealloc(PyDescrObject *descr)\r | |
8 | {\r | |
9 | _PyObject_GC_UNTRACK(descr);\r | |
10 | Py_XDECREF(descr->d_type);\r | |
11 | Py_XDECREF(descr->d_name);\r | |
12 | PyObject_GC_Del(descr);\r | |
13 | }\r | |
14 | \r | |
15 | static char *\r | |
16 | descr_name(PyDescrObject *descr)\r | |
17 | {\r | |
18 | if (descr->d_name != NULL && PyString_Check(descr->d_name))\r | |
19 | return PyString_AS_STRING(descr->d_name);\r | |
20 | else\r | |
21 | return "?";\r | |
22 | }\r | |
23 | \r | |
24 | static PyObject *\r | |
25 | descr_repr(PyDescrObject *descr, char *format)\r | |
26 | {\r | |
27 | return PyString_FromFormat(format, descr_name(descr),\r | |
28 | descr->d_type->tp_name);\r | |
29 | }\r | |
30 | \r | |
31 | static PyObject *\r | |
32 | method_repr(PyMethodDescrObject *descr)\r | |
33 | {\r | |
34 | return descr_repr((PyDescrObject *)descr,\r | |
35 | "<method '%s' of '%s' objects>");\r | |
36 | }\r | |
37 | \r | |
38 | static PyObject *\r | |
39 | member_repr(PyMemberDescrObject *descr)\r | |
40 | {\r | |
41 | return descr_repr((PyDescrObject *)descr,\r | |
42 | "<member '%s' of '%s' objects>");\r | |
43 | }\r | |
44 | \r | |
45 | static PyObject *\r | |
46 | getset_repr(PyGetSetDescrObject *descr)\r | |
47 | {\r | |
48 | return descr_repr((PyDescrObject *)descr,\r | |
49 | "<attribute '%s' of '%s' objects>");\r | |
50 | }\r | |
51 | \r | |
52 | static PyObject *\r | |
53 | wrapperdescr_repr(PyWrapperDescrObject *descr)\r | |
54 | {\r | |
55 | return descr_repr((PyDescrObject *)descr,\r | |
56 | "<slot wrapper '%s' of '%s' objects>");\r | |
57 | }\r | |
58 | \r | |
59 | static int\r | |
60 | descr_check(PyDescrObject *descr, PyObject *obj, PyObject **pres)\r | |
61 | {\r | |
62 | if (obj == NULL) {\r | |
63 | Py_INCREF(descr);\r | |
64 | *pres = (PyObject *)descr;\r | |
65 | return 1;\r | |
66 | }\r | |
67 | if (!PyObject_TypeCheck(obj, descr->d_type)) {\r | |
68 | PyErr_Format(PyExc_TypeError,\r | |
69 | "descriptor '%s' for '%s' objects "\r | |
70 | "doesn't apply to '%s' object",\r | |
71 | descr_name((PyDescrObject *)descr),\r | |
72 | descr->d_type->tp_name,\r | |
73 | obj->ob_type->tp_name);\r | |
74 | *pres = NULL;\r | |
75 | return 1;\r | |
76 | }\r | |
77 | return 0;\r | |
78 | }\r | |
79 | \r | |
80 | static PyObject *\r | |
81 | classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type)\r | |
82 | {\r | |
83 | /* Ensure a valid type. Class methods ignore obj. */\r | |
84 | if (type == NULL) {\r | |
85 | if (obj != NULL)\r | |
86 | type = (PyObject *)obj->ob_type;\r | |
87 | else {\r | |
88 | /* Wot - no type?! */\r | |
89 | PyErr_Format(PyExc_TypeError,\r | |
90 | "descriptor '%s' for type '%s' "\r | |
91 | "needs either an object or a type",\r | |
92 | descr_name((PyDescrObject *)descr),\r | |
93 | descr->d_type->tp_name);\r | |
94 | return NULL;\r | |
95 | }\r | |
96 | }\r | |
97 | if (!PyType_Check(type)) {\r | |
98 | PyErr_Format(PyExc_TypeError,\r | |
99 | "descriptor '%s' for type '%s' "\r | |
100 | "needs a type, not a '%s' as arg 2",\r | |
101 | descr_name((PyDescrObject *)descr),\r | |
102 | descr->d_type->tp_name,\r | |
103 | type->ob_type->tp_name);\r | |
104 | return NULL;\r | |
105 | }\r | |
106 | if (!PyType_IsSubtype((PyTypeObject *)type, descr->d_type)) {\r | |
107 | PyErr_Format(PyExc_TypeError,\r | |
108 | "descriptor '%s' for type '%s' "\r | |
109 | "doesn't apply to type '%s'",\r | |
110 | descr_name((PyDescrObject *)descr),\r | |
111 | descr->d_type->tp_name,\r | |
112 | ((PyTypeObject *)type)->tp_name);\r | |
113 | return NULL;\r | |
114 | }\r | |
115 | return PyCFunction_New(descr->d_method, type);\r | |
116 | }\r | |
117 | \r | |
118 | static PyObject *\r | |
119 | method_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type)\r | |
120 | {\r | |
121 | PyObject *res;\r | |
122 | \r | |
123 | if (descr_check((PyDescrObject *)descr, obj, &res))\r | |
124 | return res;\r | |
125 | return PyCFunction_New(descr->d_method, obj);\r | |
126 | }\r | |
127 | \r | |
128 | static PyObject *\r | |
129 | member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type)\r | |
130 | {\r | |
131 | PyObject *res;\r | |
132 | \r | |
133 | if (descr_check((PyDescrObject *)descr, obj, &res))\r | |
134 | return res;\r | |
135 | return PyMember_GetOne((char *)obj, descr->d_member);\r | |
136 | }\r | |
137 | \r | |
138 | static PyObject *\r | |
139 | getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type)\r | |
140 | {\r | |
141 | PyObject *res;\r | |
142 | \r | |
143 | if (descr_check((PyDescrObject *)descr, obj, &res))\r | |
144 | return res;\r | |
145 | if (descr->d_getset->get != NULL)\r | |
146 | return descr->d_getset->get(obj, descr->d_getset->closure);\r | |
147 | PyErr_Format(PyExc_AttributeError,\r | |
148 | "attribute '%.300s' of '%.100s' objects is not readable",\r | |
149 | descr_name((PyDescrObject *)descr),\r | |
150 | descr->d_type->tp_name);\r | |
151 | return NULL;\r | |
152 | }\r | |
153 | \r | |
154 | static PyObject *\r | |
155 | wrapperdescr_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type)\r | |
156 | {\r | |
157 | PyObject *res;\r | |
158 | \r | |
159 | if (descr_check((PyDescrObject *)descr, obj, &res))\r | |
160 | return res;\r | |
161 | return PyWrapper_New((PyObject *)descr, obj);\r | |
162 | }\r | |
163 | \r | |
164 | static int\r | |
165 | descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,\r | |
166 | int *pres)\r | |
167 | {\r | |
168 | assert(obj != NULL);\r | |
169 | if (!PyObject_TypeCheck(obj, descr->d_type)) {\r | |
170 | PyErr_Format(PyExc_TypeError,\r | |
171 | "descriptor '%.200s' for '%.100s' objects "\r | |
172 | "doesn't apply to '%.100s' object",\r | |
173 | descr_name(descr),\r | |
174 | descr->d_type->tp_name,\r | |
175 | obj->ob_type->tp_name);\r | |
176 | *pres = -1;\r | |
177 | return 1;\r | |
178 | }\r | |
179 | return 0;\r | |
180 | }\r | |
181 | \r | |
182 | static int\r | |
183 | member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value)\r | |
184 | {\r | |
185 | int res;\r | |
186 | \r | |
187 | if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))\r | |
188 | return res;\r | |
189 | return PyMember_SetOne((char *)obj, descr->d_member, value);\r | |
190 | }\r | |
191 | \r | |
192 | static int\r | |
193 | getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)\r | |
194 | {\r | |
195 | int res;\r | |
196 | \r | |
197 | if (descr_setcheck((PyDescrObject *)descr, obj, value, &res))\r | |
198 | return res;\r | |
199 | if (descr->d_getset->set != NULL)\r | |
200 | return descr->d_getset->set(obj, value,\r | |
201 | descr->d_getset->closure);\r | |
202 | PyErr_Format(PyExc_AttributeError,\r | |
203 | "attribute '%.300s' of '%.100s' objects is not writable",\r | |
204 | descr_name((PyDescrObject *)descr),\r | |
205 | descr->d_type->tp_name);\r | |
206 | return -1;\r | |
207 | }\r | |
208 | \r | |
209 | static PyObject *\r | |
210 | methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds)\r | |
211 | {\r | |
212 | Py_ssize_t argc;\r | |
213 | PyObject *self, *func, *result;\r | |
214 | \r | |
215 | /* Make sure that the first argument is acceptable as 'self' */\r | |
216 | assert(PyTuple_Check(args));\r | |
217 | argc = PyTuple_GET_SIZE(args);\r | |
218 | if (argc < 1) {\r | |
219 | PyErr_Format(PyExc_TypeError,\r | |
220 | "descriptor '%.300s' of '%.100s' "\r | |
221 | "object needs an argument",\r | |
222 | descr_name((PyDescrObject *)descr),\r | |
223 | descr->d_type->tp_name);\r | |
224 | return NULL;\r | |
225 | }\r | |
226 | self = PyTuple_GET_ITEM(args, 0);\r | |
227 | if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),\r | |
228 | (PyObject *)(descr->d_type))) {\r | |
229 | PyErr_Format(PyExc_TypeError,\r | |
230 | "descriptor '%.200s' "\r | |
231 | "requires a '%.100s' object "\r | |
232 | "but received a '%.100s'",\r | |
233 | descr_name((PyDescrObject *)descr),\r | |
234 | descr->d_type->tp_name,\r | |
235 | self->ob_type->tp_name);\r | |
236 | return NULL;\r | |
237 | }\r | |
238 | \r | |
239 | func = PyCFunction_New(descr->d_method, self);\r | |
240 | if (func == NULL)\r | |
241 | return NULL;\r | |
242 | args = PyTuple_GetSlice(args, 1, argc);\r | |
243 | if (args == NULL) {\r | |
244 | Py_DECREF(func);\r | |
245 | return NULL;\r | |
246 | }\r | |
247 | result = PyEval_CallObjectWithKeywords(func, args, kwds);\r | |
248 | Py_DECREF(args);\r | |
249 | Py_DECREF(func);\r | |
250 | return result;\r | |
251 | }\r | |
252 | \r | |
253 | static PyObject *\r | |
254 | classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,\r | |
255 | PyObject *kwds)\r | |
256 | {\r | |
257 | Py_ssize_t argc;\r | |
258 | PyObject *self, *func, *result;\r | |
259 | \r | |
260 | /* Make sure that the first argument is acceptable as 'self' */\r | |
261 | assert(PyTuple_Check(args));\r | |
262 | argc = PyTuple_GET_SIZE(args);\r | |
263 | if (argc < 1) {\r | |
264 | PyErr_Format(PyExc_TypeError,\r | |
265 | "descriptor '%s' of '%.100s' "\r | |
266 | "object needs an argument",\r | |
267 | descr_name((PyDescrObject *)descr),\r | |
268 | descr->d_type->tp_name);\r | |
269 | return NULL;\r | |
270 | }\r | |
271 | self = PyTuple_GET_ITEM(args, 0);\r | |
272 | if (!PyType_Check(self)) {\r | |
273 | PyErr_Format(PyExc_TypeError,\r | |
274 | "descriptor '%s' requires a type "\r | |
275 | "but received a '%.100s'",\r | |
276 | descr_name((PyDescrObject *)descr),\r | |
277 | self->ob_type->tp_name);\r | |
278 | return NULL;\r | |
279 | }\r | |
280 | if (!PyType_IsSubtype((PyTypeObject *)self, descr->d_type)) {\r | |
281 | PyErr_Format(PyExc_TypeError,\r | |
282 | "descriptor '%s' "\r | |
283 | "requires a subtype of '%.100s' "\r | |
284 | "but received '%.100s",\r | |
285 | descr_name((PyDescrObject *)descr),\r | |
286 | descr->d_type->tp_name,\r | |
287 | self->ob_type->tp_name);\r | |
288 | return NULL;\r | |
289 | }\r | |
290 | \r | |
291 | func = PyCFunction_New(descr->d_method, self);\r | |
292 | if (func == NULL)\r | |
293 | return NULL;\r | |
294 | args = PyTuple_GetSlice(args, 1, argc);\r | |
295 | if (args == NULL) {\r | |
296 | Py_DECREF(func);\r | |
297 | return NULL;\r | |
298 | }\r | |
299 | result = PyEval_CallObjectWithKeywords(func, args, kwds);\r | |
300 | Py_DECREF(func);\r | |
301 | Py_DECREF(args);\r | |
302 | return result;\r | |
303 | }\r | |
304 | \r | |
305 | static PyObject *\r | |
306 | wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)\r | |
307 | {\r | |
308 | Py_ssize_t argc;\r | |
309 | PyObject *self, *func, *result;\r | |
310 | \r | |
311 | /* Make sure that the first argument is acceptable as 'self' */\r | |
312 | assert(PyTuple_Check(args));\r | |
313 | argc = PyTuple_GET_SIZE(args);\r | |
314 | if (argc < 1) {\r | |
315 | PyErr_Format(PyExc_TypeError,\r | |
316 | "descriptor '%.300s' of '%.100s' "\r | |
317 | "object needs an argument",\r | |
318 | descr_name((PyDescrObject *)descr),\r | |
319 | descr->d_type->tp_name);\r | |
320 | return NULL;\r | |
321 | }\r | |
322 | self = PyTuple_GET_ITEM(args, 0);\r | |
323 | if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),\r | |
324 | (PyObject *)(descr->d_type))) {\r | |
325 | PyErr_Format(PyExc_TypeError,\r | |
326 | "descriptor '%.200s' "\r | |
327 | "requires a '%.100s' object "\r | |
328 | "but received a '%.100s'",\r | |
329 | descr_name((PyDescrObject *)descr),\r | |
330 | descr->d_type->tp_name,\r | |
331 | self->ob_type->tp_name);\r | |
332 | return NULL;\r | |
333 | }\r | |
334 | \r | |
335 | func = PyWrapper_New((PyObject *)descr, self);\r | |
336 | if (func == NULL)\r | |
337 | return NULL;\r | |
338 | args = PyTuple_GetSlice(args, 1, argc);\r | |
339 | if (args == NULL) {\r | |
340 | Py_DECREF(func);\r | |
341 | return NULL;\r | |
342 | }\r | |
343 | result = PyEval_CallObjectWithKeywords(func, args, kwds);\r | |
344 | Py_DECREF(args);\r | |
345 | Py_DECREF(func);\r | |
346 | return result;\r | |
347 | }\r | |
348 | \r | |
349 | static PyObject *\r | |
350 | method_get_doc(PyMethodDescrObject *descr, void *closure)\r | |
351 | {\r | |
352 | if (descr->d_method->ml_doc == NULL) {\r | |
353 | Py_INCREF(Py_None);\r | |
354 | return Py_None;\r | |
355 | }\r | |
356 | return PyString_FromString(descr->d_method->ml_doc);\r | |
357 | }\r | |
358 | \r | |
359 | static PyMemberDef descr_members[] = {\r | |
360 | {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},\r | |
361 | {"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},\r | |
362 | {0}\r | |
363 | };\r | |
364 | \r | |
365 | static PyGetSetDef method_getset[] = {\r | |
366 | {"__doc__", (getter)method_get_doc},\r | |
367 | {0}\r | |
368 | };\r | |
369 | \r | |
370 | static PyObject *\r | |
371 | member_get_doc(PyMemberDescrObject *descr, void *closure)\r | |
372 | {\r | |
373 | if (descr->d_member->doc == NULL) {\r | |
374 | Py_INCREF(Py_None);\r | |
375 | return Py_None;\r | |
376 | }\r | |
377 | return PyString_FromString(descr->d_member->doc);\r | |
378 | }\r | |
379 | \r | |
380 | static PyGetSetDef member_getset[] = {\r | |
381 | {"__doc__", (getter)member_get_doc},\r | |
382 | {0}\r | |
383 | };\r | |
384 | \r | |
385 | static PyObject *\r | |
386 | getset_get_doc(PyGetSetDescrObject *descr, void *closure)\r | |
387 | {\r | |
388 | if (descr->d_getset->doc == NULL) {\r | |
389 | Py_INCREF(Py_None);\r | |
390 | return Py_None;\r | |
391 | }\r | |
392 | return PyString_FromString(descr->d_getset->doc);\r | |
393 | }\r | |
394 | \r | |
395 | static PyGetSetDef getset_getset[] = {\r | |
396 | {"__doc__", (getter)getset_get_doc},\r | |
397 | {0}\r | |
398 | };\r | |
399 | \r | |
400 | static PyObject *\r | |
401 | wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure)\r | |
402 | {\r | |
403 | if (descr->d_base->doc == NULL) {\r | |
404 | Py_INCREF(Py_None);\r | |
405 | return Py_None;\r | |
406 | }\r | |
407 | return PyString_FromString(descr->d_base->doc);\r | |
408 | }\r | |
409 | \r | |
410 | static PyGetSetDef wrapperdescr_getset[] = {\r | |
411 | {"__doc__", (getter)wrapperdescr_get_doc},\r | |
412 | {0}\r | |
413 | };\r | |
414 | \r | |
415 | static int\r | |
416 | descr_traverse(PyObject *self, visitproc visit, void *arg)\r | |
417 | {\r | |
418 | PyDescrObject *descr = (PyDescrObject *)self;\r | |
419 | Py_VISIT(descr->d_type);\r | |
420 | return 0;\r | |
421 | }\r | |
422 | \r | |
423 | static PyTypeObject PyMethodDescr_Type = {\r | |
424 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
425 | "method_descriptor",\r | |
426 | sizeof(PyMethodDescrObject),\r | |
427 | 0,\r | |
428 | (destructor)descr_dealloc, /* tp_dealloc */\r | |
429 | 0, /* tp_print */\r | |
430 | 0, /* tp_getattr */\r | |
431 | 0, /* tp_setattr */\r | |
432 | 0, /* tp_compare */\r | |
433 | (reprfunc)method_repr, /* tp_repr */\r | |
434 | 0, /* tp_as_number */\r | |
435 | 0, /* tp_as_sequence */\r | |
436 | 0, /* tp_as_mapping */\r | |
437 | 0, /* tp_hash */\r | |
438 | (ternaryfunc)methoddescr_call, /* tp_call */\r | |
439 | 0, /* tp_str */\r | |
440 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
441 | 0, /* tp_setattro */\r | |
442 | 0, /* tp_as_buffer */\r | |
443 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
444 | 0, /* tp_doc */\r | |
445 | descr_traverse, /* tp_traverse */\r | |
446 | 0, /* tp_clear */\r | |
447 | 0, /* tp_richcompare */\r | |
448 | 0, /* tp_weaklistoffset */\r | |
449 | 0, /* tp_iter */\r | |
450 | 0, /* tp_iternext */\r | |
451 | 0, /* tp_methods */\r | |
452 | descr_members, /* tp_members */\r | |
453 | method_getset, /* tp_getset */\r | |
454 | 0, /* tp_base */\r | |
455 | 0, /* tp_dict */\r | |
456 | (descrgetfunc)method_get, /* tp_descr_get */\r | |
457 | 0, /* tp_descr_set */\r | |
458 | };\r | |
459 | \r | |
460 | /* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */\r | |
461 | static PyTypeObject PyClassMethodDescr_Type = {\r | |
462 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
463 | "classmethod_descriptor",\r | |
464 | sizeof(PyMethodDescrObject),\r | |
465 | 0,\r | |
466 | (destructor)descr_dealloc, /* tp_dealloc */\r | |
467 | 0, /* tp_print */\r | |
468 | 0, /* tp_getattr */\r | |
469 | 0, /* tp_setattr */\r | |
470 | 0, /* tp_compare */\r | |
471 | (reprfunc)method_repr, /* tp_repr */\r | |
472 | 0, /* tp_as_number */\r | |
473 | 0, /* tp_as_sequence */\r | |
474 | 0, /* tp_as_mapping */\r | |
475 | 0, /* tp_hash */\r | |
476 | (ternaryfunc)classmethoddescr_call, /* tp_call */\r | |
477 | 0, /* tp_str */\r | |
478 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
479 | 0, /* tp_setattro */\r | |
480 | 0, /* tp_as_buffer */\r | |
481 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
482 | 0, /* tp_doc */\r | |
483 | descr_traverse, /* tp_traverse */\r | |
484 | 0, /* tp_clear */\r | |
485 | 0, /* tp_richcompare */\r | |
486 | 0, /* tp_weaklistoffset */\r | |
487 | 0, /* tp_iter */\r | |
488 | 0, /* tp_iternext */\r | |
489 | 0, /* tp_methods */\r | |
490 | descr_members, /* tp_members */\r | |
491 | method_getset, /* tp_getset */\r | |
492 | 0, /* tp_base */\r | |
493 | 0, /* tp_dict */\r | |
494 | (descrgetfunc)classmethod_get, /* tp_descr_get */\r | |
495 | 0, /* tp_descr_set */\r | |
496 | };\r | |
497 | \r | |
498 | PyTypeObject PyMemberDescr_Type = {\r | |
499 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
500 | "member_descriptor",\r | |
501 | sizeof(PyMemberDescrObject),\r | |
502 | 0,\r | |
503 | (destructor)descr_dealloc, /* tp_dealloc */\r | |
504 | 0, /* tp_print */\r | |
505 | 0, /* tp_getattr */\r | |
506 | 0, /* tp_setattr */\r | |
507 | 0, /* tp_compare */\r | |
508 | (reprfunc)member_repr, /* tp_repr */\r | |
509 | 0, /* tp_as_number */\r | |
510 | 0, /* tp_as_sequence */\r | |
511 | 0, /* tp_as_mapping */\r | |
512 | 0, /* tp_hash */\r | |
513 | 0, /* tp_call */\r | |
514 | 0, /* tp_str */\r | |
515 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
516 | 0, /* tp_setattro */\r | |
517 | 0, /* tp_as_buffer */\r | |
518 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
519 | 0, /* tp_doc */\r | |
520 | descr_traverse, /* tp_traverse */\r | |
521 | 0, /* tp_clear */\r | |
522 | 0, /* tp_richcompare */\r | |
523 | 0, /* tp_weaklistoffset */\r | |
524 | 0, /* tp_iter */\r | |
525 | 0, /* tp_iternext */\r | |
526 | 0, /* tp_methods */\r | |
527 | descr_members, /* tp_members */\r | |
528 | member_getset, /* tp_getset */\r | |
529 | 0, /* tp_base */\r | |
530 | 0, /* tp_dict */\r | |
531 | (descrgetfunc)member_get, /* tp_descr_get */\r | |
532 | (descrsetfunc)member_set, /* tp_descr_set */\r | |
533 | };\r | |
534 | \r | |
535 | PyTypeObject PyGetSetDescr_Type = {\r | |
536 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
537 | "getset_descriptor",\r | |
538 | sizeof(PyGetSetDescrObject),\r | |
539 | 0,\r | |
540 | (destructor)descr_dealloc, /* tp_dealloc */\r | |
541 | 0, /* tp_print */\r | |
542 | 0, /* tp_getattr */\r | |
543 | 0, /* tp_setattr */\r | |
544 | 0, /* tp_compare */\r | |
545 | (reprfunc)getset_repr, /* tp_repr */\r | |
546 | 0, /* tp_as_number */\r | |
547 | 0, /* tp_as_sequence */\r | |
548 | 0, /* tp_as_mapping */\r | |
549 | 0, /* tp_hash */\r | |
550 | 0, /* tp_call */\r | |
551 | 0, /* tp_str */\r | |
552 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
553 | 0, /* tp_setattro */\r | |
554 | 0, /* tp_as_buffer */\r | |
555 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
556 | 0, /* tp_doc */\r | |
557 | descr_traverse, /* tp_traverse */\r | |
558 | 0, /* tp_clear */\r | |
559 | 0, /* tp_richcompare */\r | |
560 | 0, /* tp_weaklistoffset */\r | |
561 | 0, /* tp_iter */\r | |
562 | 0, /* tp_iternext */\r | |
563 | 0, /* tp_methods */\r | |
564 | descr_members, /* tp_members */\r | |
565 | getset_getset, /* tp_getset */\r | |
566 | 0, /* tp_base */\r | |
567 | 0, /* tp_dict */\r | |
568 | (descrgetfunc)getset_get, /* tp_descr_get */\r | |
569 | (descrsetfunc)getset_set, /* tp_descr_set */\r | |
570 | };\r | |
571 | \r | |
572 | PyTypeObject PyWrapperDescr_Type = {\r | |
573 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
574 | "wrapper_descriptor",\r | |
575 | sizeof(PyWrapperDescrObject),\r | |
576 | 0,\r | |
577 | (destructor)descr_dealloc, /* tp_dealloc */\r | |
578 | 0, /* tp_print */\r | |
579 | 0, /* tp_getattr */\r | |
580 | 0, /* tp_setattr */\r | |
581 | 0, /* tp_compare */\r | |
582 | (reprfunc)wrapperdescr_repr, /* tp_repr */\r | |
583 | 0, /* tp_as_number */\r | |
584 | 0, /* tp_as_sequence */\r | |
585 | 0, /* tp_as_mapping */\r | |
586 | 0, /* tp_hash */\r | |
587 | (ternaryfunc)wrapperdescr_call, /* tp_call */\r | |
588 | 0, /* tp_str */\r | |
589 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
590 | 0, /* tp_setattro */\r | |
591 | 0, /* tp_as_buffer */\r | |
592 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
593 | 0, /* tp_doc */\r | |
594 | descr_traverse, /* tp_traverse */\r | |
595 | 0, /* tp_clear */\r | |
596 | 0, /* tp_richcompare */\r | |
597 | 0, /* tp_weaklistoffset */\r | |
598 | 0, /* tp_iter */\r | |
599 | 0, /* tp_iternext */\r | |
600 | 0, /* tp_methods */\r | |
601 | descr_members, /* tp_members */\r | |
602 | wrapperdescr_getset, /* tp_getset */\r | |
603 | 0, /* tp_base */\r | |
604 | 0, /* tp_dict */\r | |
605 | (descrgetfunc)wrapperdescr_get, /* tp_descr_get */\r | |
606 | 0, /* tp_descr_set */\r | |
607 | };\r | |
608 | \r | |
609 | static PyDescrObject *\r | |
610 | descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)\r | |
611 | {\r | |
612 | PyDescrObject *descr;\r | |
613 | \r | |
614 | descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);\r | |
615 | if (descr != NULL) {\r | |
616 | Py_XINCREF(type);\r | |
617 | descr->d_type = type;\r | |
618 | descr->d_name = PyString_InternFromString(name);\r | |
619 | if (descr->d_name == NULL) {\r | |
620 | Py_DECREF(descr);\r | |
621 | descr = NULL;\r | |
622 | }\r | |
623 | }\r | |
624 | return descr;\r | |
625 | }\r | |
626 | \r | |
627 | PyObject *\r | |
628 | PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)\r | |
629 | {\r | |
630 | PyMethodDescrObject *descr;\r | |
631 | \r | |
632 | descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,\r | |
633 | type, method->ml_name);\r | |
634 | if (descr != NULL)\r | |
635 | descr->d_method = method;\r | |
636 | return (PyObject *)descr;\r | |
637 | }\r | |
638 | \r | |
639 | PyObject *\r | |
640 | PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)\r | |
641 | {\r | |
642 | PyMethodDescrObject *descr;\r | |
643 | \r | |
644 | descr = (PyMethodDescrObject *)descr_new(&PyClassMethodDescr_Type,\r | |
645 | type, method->ml_name);\r | |
646 | if (descr != NULL)\r | |
647 | descr->d_method = method;\r | |
648 | return (PyObject *)descr;\r | |
649 | }\r | |
650 | \r | |
651 | PyObject *\r | |
652 | PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member)\r | |
653 | {\r | |
654 | PyMemberDescrObject *descr;\r | |
655 | \r | |
656 | descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,\r | |
657 | type, member->name);\r | |
658 | if (descr != NULL)\r | |
659 | descr->d_member = member;\r | |
660 | return (PyObject *)descr;\r | |
661 | }\r | |
662 | \r | |
663 | PyObject *\r | |
664 | PyDescr_NewGetSet(PyTypeObject *type, PyGetSetDef *getset)\r | |
665 | {\r | |
666 | PyGetSetDescrObject *descr;\r | |
667 | \r | |
668 | descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,\r | |
669 | type, getset->name);\r | |
670 | if (descr != NULL)\r | |
671 | descr->d_getset = getset;\r | |
672 | return (PyObject *)descr;\r | |
673 | }\r | |
674 | \r | |
675 | PyObject *\r | |
676 | PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)\r | |
677 | {\r | |
678 | PyWrapperDescrObject *descr;\r | |
679 | \r | |
680 | descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,\r | |
681 | type, base->name);\r | |
682 | if (descr != NULL) {\r | |
683 | descr->d_base = base;\r | |
684 | descr->d_wrapped = wrapped;\r | |
685 | }\r | |
686 | return (PyObject *)descr;\r | |
687 | }\r | |
688 | \r | |
689 | \r | |
690 | /* --- Readonly proxy for dictionaries (actually any mapping) --- */\r | |
691 | \r | |
692 | /* This has no reason to be in this file except that adding new files is a\r | |
693 | bit of a pain */\r | |
694 | \r | |
695 | typedef struct {\r | |
696 | PyObject_HEAD\r | |
697 | PyObject *dict;\r | |
698 | } proxyobject;\r | |
699 | \r | |
700 | static Py_ssize_t\r | |
701 | proxy_len(proxyobject *pp)\r | |
702 | {\r | |
703 | return PyObject_Size(pp->dict);\r | |
704 | }\r | |
705 | \r | |
706 | static PyObject *\r | |
707 | proxy_getitem(proxyobject *pp, PyObject *key)\r | |
708 | {\r | |
709 | return PyObject_GetItem(pp->dict, key);\r | |
710 | }\r | |
711 | \r | |
712 | static PyMappingMethods proxy_as_mapping = {\r | |
713 | (lenfunc)proxy_len, /* mp_length */\r | |
714 | (binaryfunc)proxy_getitem, /* mp_subscript */\r | |
715 | 0, /* mp_ass_subscript */\r | |
716 | };\r | |
717 | \r | |
718 | static int\r | |
719 | proxy_contains(proxyobject *pp, PyObject *key)\r | |
720 | {\r | |
721 | return PyDict_Contains(pp->dict, key);\r | |
722 | }\r | |
723 | \r | |
724 | static PySequenceMethods proxy_as_sequence = {\r | |
725 | 0, /* sq_length */\r | |
726 | 0, /* sq_concat */\r | |
727 | 0, /* sq_repeat */\r | |
728 | 0, /* sq_item */\r | |
729 | 0, /* sq_slice */\r | |
730 | 0, /* sq_ass_item */\r | |
731 | 0, /* sq_ass_slice */\r | |
732 | (objobjproc)proxy_contains, /* sq_contains */\r | |
733 | 0, /* sq_inplace_concat */\r | |
734 | 0, /* sq_inplace_repeat */\r | |
735 | };\r | |
736 | \r | |
737 | static PyObject *\r | |
738 | proxy_has_key(proxyobject *pp, PyObject *key)\r | |
739 | {\r | |
740 | int res = PyDict_Contains(pp->dict, key);\r | |
741 | if (res < 0)\r | |
742 | return NULL;\r | |
743 | return PyBool_FromLong(res);\r | |
744 | }\r | |
745 | \r | |
746 | static PyObject *\r | |
747 | proxy_get(proxyobject *pp, PyObject *args)\r | |
748 | {\r | |
749 | PyObject *key, *def = Py_None;\r | |
750 | \r | |
751 | if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def))\r | |
752 | return NULL;\r | |
753 | return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);\r | |
754 | }\r | |
755 | \r | |
756 | static PyObject *\r | |
757 | proxy_keys(proxyobject *pp)\r | |
758 | {\r | |
759 | return PyMapping_Keys(pp->dict);\r | |
760 | }\r | |
761 | \r | |
762 | static PyObject *\r | |
763 | proxy_values(proxyobject *pp)\r | |
764 | {\r | |
765 | return PyMapping_Values(pp->dict);\r | |
766 | }\r | |
767 | \r | |
768 | static PyObject *\r | |
769 | proxy_items(proxyobject *pp)\r | |
770 | {\r | |
771 | return PyMapping_Items(pp->dict);\r | |
772 | }\r | |
773 | \r | |
774 | static PyObject *\r | |
775 | proxy_iterkeys(proxyobject *pp)\r | |
776 | {\r | |
777 | return PyObject_CallMethod(pp->dict, "iterkeys", NULL);\r | |
778 | }\r | |
779 | \r | |
780 | static PyObject *\r | |
781 | proxy_itervalues(proxyobject *pp)\r | |
782 | {\r | |
783 | return PyObject_CallMethod(pp->dict, "itervalues", NULL);\r | |
784 | }\r | |
785 | \r | |
786 | static PyObject *\r | |
787 | proxy_iteritems(proxyobject *pp)\r | |
788 | {\r | |
789 | return PyObject_CallMethod(pp->dict, "iteritems", NULL);\r | |
790 | }\r | |
791 | static PyObject *\r | |
792 | proxy_copy(proxyobject *pp)\r | |
793 | {\r | |
794 | return PyObject_CallMethod(pp->dict, "copy", NULL);\r | |
795 | }\r | |
796 | \r | |
797 | static PyMethodDef proxy_methods[] = {\r | |
798 | {"has_key", (PyCFunction)proxy_has_key, METH_O,\r | |
799 | PyDoc_STR("D.has_key(k) -> True if D has a key k, else False")},\r | |
800 | {"get", (PyCFunction)proxy_get, METH_VARARGS,\r | |
801 | PyDoc_STR("D.get(k[,d]) -> D[k] if D.has_key(k), else d."\r | |
802 | " d defaults to None.")},\r | |
803 | {"keys", (PyCFunction)proxy_keys, METH_NOARGS,\r | |
804 | PyDoc_STR("D.keys() -> list of D's keys")},\r | |
805 | {"values", (PyCFunction)proxy_values, METH_NOARGS,\r | |
806 | PyDoc_STR("D.values() -> list of D's values")},\r | |
807 | {"items", (PyCFunction)proxy_items, METH_NOARGS,\r | |
808 | PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")},\r | |
809 | {"iterkeys", (PyCFunction)proxy_iterkeys, METH_NOARGS,\r | |
810 | PyDoc_STR("D.iterkeys() -> an iterator over the keys of D")},\r | |
811 | {"itervalues",(PyCFunction)proxy_itervalues, METH_NOARGS,\r | |
812 | PyDoc_STR("D.itervalues() -> an iterator over the values of D")},\r | |
813 | {"iteritems", (PyCFunction)proxy_iteritems, METH_NOARGS,\r | |
814 | PyDoc_STR("D.iteritems() ->"\r | |
815 | " an iterator over the (key, value) items of D")},\r | |
816 | {"copy", (PyCFunction)proxy_copy, METH_NOARGS,\r | |
817 | PyDoc_STR("D.copy() -> a shallow copy of D")},\r | |
818 | {0}\r | |
819 | };\r | |
820 | \r | |
821 | static void\r | |
822 | proxy_dealloc(proxyobject *pp)\r | |
823 | {\r | |
824 | _PyObject_GC_UNTRACK(pp);\r | |
825 | Py_DECREF(pp->dict);\r | |
826 | PyObject_GC_Del(pp);\r | |
827 | }\r | |
828 | \r | |
829 | static PyObject *\r | |
830 | proxy_getiter(proxyobject *pp)\r | |
831 | {\r | |
832 | return PyObject_GetIter(pp->dict);\r | |
833 | }\r | |
834 | \r | |
835 | static PyObject *\r | |
836 | proxy_str(proxyobject *pp)\r | |
837 | {\r | |
838 | return PyObject_Str(pp->dict);\r | |
839 | }\r | |
840 | \r | |
841 | static PyObject *\r | |
842 | proxy_repr(proxyobject *pp)\r | |
843 | {\r | |
844 | PyObject *dictrepr;\r | |
845 | PyObject *result;\r | |
846 | \r | |
847 | dictrepr = PyObject_Repr(pp->dict);\r | |
848 | if (dictrepr == NULL)\r | |
849 | return NULL;\r | |
850 | result = PyString_FromFormat("dict_proxy(%s)", PyString_AS_STRING(dictrepr));\r | |
851 | Py_DECREF(dictrepr);\r | |
852 | return result;\r | |
853 | }\r | |
854 | \r | |
855 | static int\r | |
856 | proxy_traverse(PyObject *self, visitproc visit, void *arg)\r | |
857 | {\r | |
858 | proxyobject *pp = (proxyobject *)self;\r | |
859 | Py_VISIT(pp->dict);\r | |
860 | return 0;\r | |
861 | }\r | |
862 | \r | |
863 | static int\r | |
864 | proxy_compare(proxyobject *v, PyObject *w)\r | |
865 | {\r | |
866 | return PyObject_Compare(v->dict, w);\r | |
867 | }\r | |
868 | \r | |
869 | static PyObject *\r | |
870 | proxy_richcompare(proxyobject *v, PyObject *w, int op)\r | |
871 | {\r | |
872 | return PyObject_RichCompare(v->dict, w, op);\r | |
873 | }\r | |
874 | \r | |
875 | PyTypeObject PyDictProxy_Type = {\r | |
876 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
877 | "dictproxy", /* tp_name */\r | |
878 | sizeof(proxyobject), /* tp_basicsize */\r | |
879 | 0, /* tp_itemsize */\r | |
880 | /* methods */\r | |
881 | (destructor)proxy_dealloc, /* tp_dealloc */\r | |
882 | 0, /* tp_print */\r | |
883 | 0, /* tp_getattr */\r | |
884 | 0, /* tp_setattr */\r | |
885 | (cmpfunc)proxy_compare, /* tp_compare */\r | |
886 | (reprfunc)proxy_repr, /* tp_repr */\r | |
887 | 0, /* tp_as_number */\r | |
888 | &proxy_as_sequence, /* tp_as_sequence */\r | |
889 | &proxy_as_mapping, /* tp_as_mapping */\r | |
890 | 0, /* tp_hash */\r | |
891 | 0, /* tp_call */\r | |
892 | (reprfunc)proxy_str, /* tp_str */\r | |
893 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
894 | 0, /* tp_setattro */\r | |
895 | 0, /* tp_as_buffer */\r | |
896 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
897 | 0, /* tp_doc */\r | |
898 | proxy_traverse, /* tp_traverse */\r | |
899 | 0, /* tp_clear */\r | |
900 | (richcmpfunc)proxy_richcompare, /* tp_richcompare */\r | |
901 | 0, /* tp_weaklistoffset */\r | |
902 | (getiterfunc)proxy_getiter, /* tp_iter */\r | |
903 | 0, /* tp_iternext */\r | |
904 | proxy_methods, /* tp_methods */\r | |
905 | 0, /* tp_members */\r | |
906 | 0, /* tp_getset */\r | |
907 | 0, /* tp_base */\r | |
908 | 0, /* tp_dict */\r | |
909 | 0, /* tp_descr_get */\r | |
910 | 0, /* tp_descr_set */\r | |
911 | };\r | |
912 | \r | |
913 | PyObject *\r | |
914 | PyDictProxy_New(PyObject *dict)\r | |
915 | {\r | |
916 | proxyobject *pp;\r | |
917 | \r | |
918 | pp = PyObject_GC_New(proxyobject, &PyDictProxy_Type);\r | |
919 | if (pp != NULL) {\r | |
920 | Py_INCREF(dict);\r | |
921 | pp->dict = dict;\r | |
922 | _PyObject_GC_TRACK(pp);\r | |
923 | }\r | |
924 | return (PyObject *)pp;\r | |
925 | }\r | |
926 | \r | |
927 | \r | |
928 | /* --- Wrapper object for "slot" methods --- */\r | |
929 | \r | |
930 | /* This has no reason to be in this file except that adding new files is a\r | |
931 | bit of a pain */\r | |
932 | \r | |
933 | typedef struct {\r | |
934 | PyObject_HEAD\r | |
935 | PyWrapperDescrObject *descr;\r | |
936 | PyObject *self;\r | |
937 | } wrapperobject;\r | |
938 | \r | |
939 | static void\r | |
940 | wrapper_dealloc(wrapperobject *wp)\r | |
941 | {\r | |
942 | PyObject_GC_UnTrack(wp);\r | |
943 | Py_TRASHCAN_SAFE_BEGIN(wp)\r | |
944 | Py_XDECREF(wp->descr);\r | |
945 | Py_XDECREF(wp->self);\r | |
946 | PyObject_GC_Del(wp);\r | |
947 | Py_TRASHCAN_SAFE_END(wp)\r | |
948 | }\r | |
949 | \r | |
950 | static int\r | |
951 | wrapper_compare(wrapperobject *a, wrapperobject *b)\r | |
952 | {\r | |
953 | if (a->descr == b->descr)\r | |
954 | return PyObject_Compare(a->self, b->self);\r | |
955 | else\r | |
956 | return (a->descr < b->descr) ? -1 : 1;\r | |
957 | }\r | |
958 | \r | |
959 | static long\r | |
960 | wrapper_hash(wrapperobject *wp)\r | |
961 | {\r | |
962 | int x, y;\r | |
963 | x = _Py_HashPointer(wp->descr);\r | |
964 | if (x == -1)\r | |
965 | return -1;\r | |
966 | y = PyObject_Hash(wp->self);\r | |
967 | if (y == -1)\r | |
968 | return -1;\r | |
969 | x = x ^ y;\r | |
970 | if (x == -1)\r | |
971 | x = -2;\r | |
972 | return x;\r | |
973 | }\r | |
974 | \r | |
975 | static PyObject *\r | |
976 | wrapper_repr(wrapperobject *wp)\r | |
977 | {\r | |
978 | return PyString_FromFormat("<method-wrapper '%s' of %s object at %p>",\r | |
979 | wp->descr->d_base->name,\r | |
980 | wp->self->ob_type->tp_name,\r | |
981 | wp->self);\r | |
982 | }\r | |
983 | \r | |
984 | static PyMemberDef wrapper_members[] = {\r | |
985 | {"__self__", T_OBJECT, offsetof(wrapperobject, self), READONLY},\r | |
986 | {0}\r | |
987 | };\r | |
988 | \r | |
989 | static PyObject *\r | |
990 | wrapper_objclass(wrapperobject *wp)\r | |
991 | {\r | |
992 | PyObject *c = (PyObject *)wp->descr->d_type;\r | |
993 | \r | |
994 | Py_INCREF(c);\r | |
995 | return c;\r | |
996 | }\r | |
997 | \r | |
998 | static PyObject *\r | |
999 | wrapper_name(wrapperobject *wp)\r | |
1000 | {\r | |
1001 | char *s = wp->descr->d_base->name;\r | |
1002 | \r | |
1003 | return PyString_FromString(s);\r | |
1004 | }\r | |
1005 | \r | |
1006 | static PyObject *\r | |
1007 | wrapper_doc(wrapperobject *wp)\r | |
1008 | {\r | |
1009 | char *s = wp->descr->d_base->doc;\r | |
1010 | \r | |
1011 | if (s == NULL) {\r | |
1012 | Py_INCREF(Py_None);\r | |
1013 | return Py_None;\r | |
1014 | }\r | |
1015 | else {\r | |
1016 | return PyString_FromString(s);\r | |
1017 | }\r | |
1018 | }\r | |
1019 | \r | |
1020 | static PyGetSetDef wrapper_getsets[] = {\r | |
1021 | {"__objclass__", (getter)wrapper_objclass},\r | |
1022 | {"__name__", (getter)wrapper_name},\r | |
1023 | {"__doc__", (getter)wrapper_doc},\r | |
1024 | {0}\r | |
1025 | };\r | |
1026 | \r | |
1027 | static PyObject *\r | |
1028 | wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)\r | |
1029 | {\r | |
1030 | wrapperfunc wrapper = wp->descr->d_base->wrapper;\r | |
1031 | PyObject *self = wp->self;\r | |
1032 | \r | |
1033 | if (wp->descr->d_base->flags & PyWrapperFlag_KEYWORDS) {\r | |
1034 | wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper;\r | |
1035 | return (*wk)(self, args, wp->descr->d_wrapped, kwds);\r | |
1036 | }\r | |
1037 | \r | |
1038 | if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) {\r | |
1039 | PyErr_Format(PyExc_TypeError,\r | |
1040 | "wrapper %s doesn't take keyword arguments",\r | |
1041 | wp->descr->d_base->name);\r | |
1042 | return NULL;\r | |
1043 | }\r | |
1044 | return (*wrapper)(self, args, wp->descr->d_wrapped);\r | |
1045 | }\r | |
1046 | \r | |
1047 | static int\r | |
1048 | wrapper_traverse(PyObject *self, visitproc visit, void *arg)\r | |
1049 | {\r | |
1050 | wrapperobject *wp = (wrapperobject *)self;\r | |
1051 | Py_VISIT(wp->descr);\r | |
1052 | Py_VISIT(wp->self);\r | |
1053 | return 0;\r | |
1054 | }\r | |
1055 | \r | |
1056 | static PyTypeObject wrappertype = {\r | |
1057 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
1058 | "method-wrapper", /* tp_name */\r | |
1059 | sizeof(wrapperobject), /* tp_basicsize */\r | |
1060 | 0, /* tp_itemsize */\r | |
1061 | /* methods */\r | |
1062 | (destructor)wrapper_dealloc, /* tp_dealloc */\r | |
1063 | 0, /* tp_print */\r | |
1064 | 0, /* tp_getattr */\r | |
1065 | 0, /* tp_setattr */\r | |
1066 | (cmpfunc)wrapper_compare, /* tp_compare */\r | |
1067 | (reprfunc)wrapper_repr, /* tp_repr */\r | |
1068 | 0, /* tp_as_number */\r | |
1069 | 0, /* tp_as_sequence */\r | |
1070 | 0, /* tp_as_mapping */\r | |
1071 | (hashfunc)wrapper_hash, /* tp_hash */\r | |
1072 | (ternaryfunc)wrapper_call, /* tp_call */\r | |
1073 | 0, /* tp_str */\r | |
1074 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
1075 | 0, /* tp_setattro */\r | |
1076 | 0, /* tp_as_buffer */\r | |
1077 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
1078 | 0, /* tp_doc */\r | |
1079 | wrapper_traverse, /* tp_traverse */\r | |
1080 | 0, /* tp_clear */\r | |
1081 | 0, /* tp_richcompare */\r | |
1082 | 0, /* tp_weaklistoffset */\r | |
1083 | 0, /* tp_iter */\r | |
1084 | 0, /* tp_iternext */\r | |
1085 | 0, /* tp_methods */\r | |
1086 | wrapper_members, /* tp_members */\r | |
1087 | wrapper_getsets, /* tp_getset */\r | |
1088 | 0, /* tp_base */\r | |
1089 | 0, /* tp_dict */\r | |
1090 | 0, /* tp_descr_get */\r | |
1091 | 0, /* tp_descr_set */\r | |
1092 | };\r | |
1093 | \r | |
1094 | PyObject *\r | |
1095 | PyWrapper_New(PyObject *d, PyObject *self)\r | |
1096 | {\r | |
1097 | wrapperobject *wp;\r | |
1098 | PyWrapperDescrObject *descr;\r | |
1099 | \r | |
1100 | assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));\r | |
1101 | descr = (PyWrapperDescrObject *)d;\r | |
1102 | assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),\r | |
1103 | (PyObject *)(descr->d_type)));\r | |
1104 | \r | |
1105 | wp = PyObject_GC_New(wrapperobject, &wrappertype);\r | |
1106 | if (wp != NULL) {\r | |
1107 | Py_INCREF(descr);\r | |
1108 | wp->descr = descr;\r | |
1109 | Py_INCREF(self);\r | |
1110 | wp->self = self;\r | |
1111 | _PyObject_GC_TRACK(wp);\r | |
1112 | }\r | |
1113 | return (PyObject *)wp;\r | |
1114 | }\r | |
1115 | \r | |
1116 | \r | |
1117 | /* A built-in 'property' type */\r | |
1118 | \r | |
1119 | /*\r | |
1120 | class property(object):\r | |
1121 | \r | |
1122 | def __init__(self, fget=None, fset=None, fdel=None, doc=None):\r | |
1123 | if doc is None and fget is not None and hasattr(fget, "__doc__"):\r | |
1124 | doc = fget.__doc__\r | |
1125 | self.__get = fget\r | |
1126 | self.__set = fset\r | |
1127 | self.__del = fdel\r | |
1128 | self.__doc__ = doc\r | |
1129 | \r | |
1130 | def __get__(self, inst, type=None):\r | |
1131 | if inst is None:\r | |
1132 | return self\r | |
1133 | if self.__get is None:\r | |
1134 | raise AttributeError, "unreadable attribute"\r | |
1135 | return self.__get(inst)\r | |
1136 | \r | |
1137 | def __set__(self, inst, value):\r | |
1138 | if self.__set is None:\r | |
1139 | raise AttributeError, "can't set attribute"\r | |
1140 | return self.__set(inst, value)\r | |
1141 | \r | |
1142 | def __delete__(self, inst):\r | |
1143 | if self.__del is None:\r | |
1144 | raise AttributeError, "can't delete attribute"\r | |
1145 | return self.__del(inst)\r | |
1146 | \r | |
1147 | */\r | |
1148 | \r | |
1149 | typedef struct {\r | |
1150 | PyObject_HEAD\r | |
1151 | PyObject *prop_get;\r | |
1152 | PyObject *prop_set;\r | |
1153 | PyObject *prop_del;\r | |
1154 | PyObject *prop_doc;\r | |
1155 | int getter_doc;\r | |
1156 | } propertyobject;\r | |
1157 | \r | |
1158 | static PyObject * property_copy(PyObject *, PyObject *, PyObject *,\r | |
1159 | PyObject *);\r | |
1160 | \r | |
1161 | static PyMemberDef property_members[] = {\r | |
1162 | {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY},\r | |
1163 | {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY},\r | |
1164 | {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY},\r | |
1165 | {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY},\r | |
1166 | {0}\r | |
1167 | };\r | |
1168 | \r | |
1169 | \r | |
1170 | PyDoc_STRVAR(getter_doc,\r | |
1171 | "Descriptor to change the getter on a property.");\r | |
1172 | \r | |
1173 | static PyObject *\r | |
1174 | property_getter(PyObject *self, PyObject *getter)\r | |
1175 | {\r | |
1176 | return property_copy(self, getter, NULL, NULL);\r | |
1177 | }\r | |
1178 | \r | |
1179 | \r | |
1180 | PyDoc_STRVAR(setter_doc,\r | |
1181 | "Descriptor to change the setter on a property.");\r | |
1182 | \r | |
1183 | static PyObject *\r | |
1184 | property_setter(PyObject *self, PyObject *setter)\r | |
1185 | {\r | |
1186 | return property_copy(self, NULL, setter, NULL);\r | |
1187 | }\r | |
1188 | \r | |
1189 | \r | |
1190 | PyDoc_STRVAR(deleter_doc,\r | |
1191 | "Descriptor to change the deleter on a property.");\r | |
1192 | \r | |
1193 | static PyObject *\r | |
1194 | property_deleter(PyObject *self, PyObject *deleter)\r | |
1195 | {\r | |
1196 | return property_copy(self, NULL, NULL, deleter);\r | |
1197 | }\r | |
1198 | \r | |
1199 | \r | |
1200 | static PyMethodDef property_methods[] = {\r | |
1201 | {"getter", property_getter, METH_O, getter_doc},\r | |
1202 | {"setter", property_setter, METH_O, setter_doc},\r | |
1203 | {"deleter", property_deleter, METH_O, deleter_doc},\r | |
1204 | {0}\r | |
1205 | };\r | |
1206 | \r | |
1207 | \r | |
1208 | static void\r | |
1209 | property_dealloc(PyObject *self)\r | |
1210 | {\r | |
1211 | propertyobject *gs = (propertyobject *)self;\r | |
1212 | \r | |
1213 | _PyObject_GC_UNTRACK(self);\r | |
1214 | Py_XDECREF(gs->prop_get);\r | |
1215 | Py_XDECREF(gs->prop_set);\r | |
1216 | Py_XDECREF(gs->prop_del);\r | |
1217 | Py_XDECREF(gs->prop_doc);\r | |
1218 | self->ob_type->tp_free(self);\r | |
1219 | }\r | |
1220 | \r | |
1221 | static PyObject *\r | |
1222 | property_descr_get(PyObject *self, PyObject *obj, PyObject *type)\r | |
1223 | {\r | |
1224 | propertyobject *gs = (propertyobject *)self;\r | |
1225 | \r | |
1226 | if (obj == NULL || obj == Py_None) {\r | |
1227 | Py_INCREF(self);\r | |
1228 | return self;\r | |
1229 | }\r | |
1230 | if (gs->prop_get == NULL) {\r | |
1231 | PyErr_SetString(PyExc_AttributeError, "unreadable attribute");\r | |
1232 | return NULL;\r | |
1233 | }\r | |
1234 | return PyObject_CallFunction(gs->prop_get, "(O)", obj);\r | |
1235 | }\r | |
1236 | \r | |
1237 | static int\r | |
1238 | property_descr_set(PyObject *self, PyObject *obj, PyObject *value)\r | |
1239 | {\r | |
1240 | propertyobject *gs = (propertyobject *)self;\r | |
1241 | PyObject *func, *res;\r | |
1242 | \r | |
1243 | if (value == NULL)\r | |
1244 | func = gs->prop_del;\r | |
1245 | else\r | |
1246 | func = gs->prop_set;\r | |
1247 | if (func == NULL) {\r | |
1248 | PyErr_SetString(PyExc_AttributeError,\r | |
1249 | value == NULL ?\r | |
1250 | "can't delete attribute" :\r | |
1251 | "can't set attribute");\r | |
1252 | return -1;\r | |
1253 | }\r | |
1254 | if (value == NULL)\r | |
1255 | res = PyObject_CallFunction(func, "(O)", obj);\r | |
1256 | else\r | |
1257 | res = PyObject_CallFunction(func, "(OO)", obj, value);\r | |
1258 | if (res == NULL)\r | |
1259 | return -1;\r | |
1260 | Py_DECREF(res);\r | |
1261 | return 0;\r | |
1262 | }\r | |
1263 | \r | |
1264 | static PyObject *\r | |
1265 | property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *del)\r | |
1266 | {\r | |
1267 | propertyobject *pold = (propertyobject *)old;\r | |
1268 | PyObject *new, *type, *doc;\r | |
1269 | \r | |
1270 | type = PyObject_Type(old);\r | |
1271 | if (type == NULL)\r | |
1272 | return NULL;\r | |
1273 | \r | |
1274 | if (get == NULL || get == Py_None) {\r | |
1275 | Py_XDECREF(get);\r | |
1276 | get = pold->prop_get ? pold->prop_get : Py_None;\r | |
1277 | }\r | |
1278 | if (set == NULL || set == Py_None) {\r | |
1279 | Py_XDECREF(set);\r | |
1280 | set = pold->prop_set ? pold->prop_set : Py_None;\r | |
1281 | }\r | |
1282 | if (del == NULL || del == Py_None) {\r | |
1283 | Py_XDECREF(del);\r | |
1284 | del = pold->prop_del ? pold->prop_del : Py_None;\r | |
1285 | }\r | |
1286 | if (pold->getter_doc && get != Py_None) {\r | |
1287 | /* make _init use __doc__ from getter */\r | |
1288 | doc = Py_None;\r | |
1289 | }\r | |
1290 | else {\r | |
1291 | doc = pold->prop_doc ? pold->prop_doc : Py_None;\r | |
1292 | }\r | |
1293 | \r | |
1294 | new = PyObject_CallFunction(type, "OOOO", get, set, del, doc);\r | |
1295 | Py_DECREF(type);\r | |
1296 | if (new == NULL)\r | |
1297 | return NULL;\r | |
1298 | return new;\r | |
1299 | }\r | |
1300 | \r | |
1301 | static int\r | |
1302 | property_init(PyObject *self, PyObject *args, PyObject *kwds)\r | |
1303 | {\r | |
1304 | PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL;\r | |
1305 | static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0};\r | |
1306 | propertyobject *prop = (propertyobject *)self;\r | |
1307 | \r | |
1308 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property",\r | |
1309 | kwlist, &get, &set, &del, &doc))\r | |
1310 | return -1;\r | |
1311 | \r | |
1312 | if (get == Py_None)\r | |
1313 | get = NULL;\r | |
1314 | if (set == Py_None)\r | |
1315 | set = NULL;\r | |
1316 | if (del == Py_None)\r | |
1317 | del = NULL;\r | |
1318 | \r | |
1319 | Py_XINCREF(get);\r | |
1320 | Py_XINCREF(set);\r | |
1321 | Py_XINCREF(del);\r | |
1322 | Py_XINCREF(doc);\r | |
1323 | \r | |
1324 | prop->prop_get = get;\r | |
1325 | prop->prop_set = set;\r | |
1326 | prop->prop_del = del;\r | |
1327 | prop->prop_doc = doc;\r | |
1328 | prop->getter_doc = 0;\r | |
1329 | \r | |
1330 | /* if no docstring given and the getter has one, use that one */\r | |
1331 | if ((doc == NULL || doc == Py_None) && get != NULL) {\r | |
1332 | PyObject *get_doc = PyObject_GetAttrString(get, "__doc__");\r | |
1333 | if (get_doc) {\r | |
1334 | if (Py_TYPE(self) == &PyProperty_Type) {\r | |
1335 | Py_XDECREF(prop->prop_doc);\r | |
1336 | prop->prop_doc = get_doc;\r | |
1337 | }\r | |
1338 | else {\r | |
1339 | /* If this is a property subclass, put __doc__\r | |
1340 | in dict of the subclass instance instead,\r | |
1341 | otherwise it gets shadowed by __doc__ in the\r | |
1342 | class's dict. */\r | |
1343 | int err = PyObject_SetAttrString(self, "__doc__", get_doc);\r | |
1344 | Py_DECREF(get_doc);\r | |
1345 | if (err < 0)\r | |
1346 | return -1;\r | |
1347 | }\r | |
1348 | prop->getter_doc = 1;\r | |
1349 | }\r | |
1350 | else if (PyErr_ExceptionMatches(PyExc_Exception)) {\r | |
1351 | PyErr_Clear();\r | |
1352 | }\r | |
1353 | else {\r | |
1354 | return -1;\r | |
1355 | }\r | |
1356 | }\r | |
1357 | \r | |
1358 | return 0;\r | |
1359 | }\r | |
1360 | \r | |
1361 | PyDoc_STRVAR(property_doc,\r | |
1362 | "property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n"\r | |
1363 | "\n"\r | |
1364 | "fget is a function to be used for getting an attribute value, and likewise\n"\r | |
1365 | "fset is a function for setting, and fdel a function for del'ing, an\n"\r | |
1366 | "attribute. Typical use is to define a managed attribute x:\n\n"\r | |
1367 | "class C(object):\n"\r | |
1368 | " def getx(self): return self._x\n"\r | |
1369 | " def setx(self, value): self._x = value\n"\r | |
1370 | " def delx(self): del self._x\n"\r | |
1371 | " x = property(getx, setx, delx, \"I'm the 'x' property.\")\n"\r | |
1372 | "\n"\r | |
1373 | "Decorators make defining new properties or modifying existing ones easy:\n\n"\r | |
1374 | "class C(object):\n"\r | |
1375 | " @property\n"\r | |
1376 | " def x(self):\n"\r | |
1377 | " \"I am the 'x' property.\"\n"\r | |
1378 | " return self._x\n"\r | |
1379 | " @x.setter\n"\r | |
1380 | " def x(self, value):\n"\r | |
1381 | " self._x = value\n"\r | |
1382 | " @x.deleter\n"\r | |
1383 | " def x(self):\n"\r | |
1384 | " del self._x\n"\r | |
1385 | );\r | |
1386 | \r | |
1387 | static int\r | |
1388 | property_traverse(PyObject *self, visitproc visit, void *arg)\r | |
1389 | {\r | |
1390 | propertyobject *pp = (propertyobject *)self;\r | |
1391 | Py_VISIT(pp->prop_get);\r | |
1392 | Py_VISIT(pp->prop_set);\r | |
1393 | Py_VISIT(pp->prop_del);\r | |
1394 | Py_VISIT(pp->prop_doc);\r | |
1395 | return 0;\r | |
1396 | }\r | |
1397 | \r | |
1398 | PyTypeObject PyProperty_Type = {\r | |
1399 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
1400 | "property", /* tp_name */\r | |
1401 | sizeof(propertyobject), /* tp_basicsize */\r | |
1402 | 0, /* tp_itemsize */\r | |
1403 | /* methods */\r | |
1404 | property_dealloc, /* tp_dealloc */\r | |
1405 | 0, /* tp_print */\r | |
1406 | 0, /* tp_getattr */\r | |
1407 | 0, /* tp_setattr */\r | |
1408 | 0, /* tp_compare */\r | |
1409 | 0, /* tp_repr */\r | |
1410 | 0, /* tp_as_number */\r | |
1411 | 0, /* tp_as_sequence */\r | |
1412 | 0, /* tp_as_mapping */\r | |
1413 | 0, /* tp_hash */\r | |
1414 | 0, /* tp_call */\r | |
1415 | 0, /* tp_str */\r | |
1416 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
1417 | 0, /* tp_setattro */\r | |
1418 | 0, /* tp_as_buffer */\r | |
1419 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |\r | |
1420 | Py_TPFLAGS_BASETYPE, /* tp_flags */\r | |
1421 | property_doc, /* tp_doc */\r | |
1422 | property_traverse, /* tp_traverse */\r | |
1423 | 0, /* tp_clear */\r | |
1424 | 0, /* tp_richcompare */\r | |
1425 | 0, /* tp_weaklistoffset */\r | |
1426 | 0, /* tp_iter */\r | |
1427 | 0, /* tp_iternext */\r | |
1428 | property_methods, /* tp_methods */\r | |
1429 | property_members, /* tp_members */\r | |
1430 | 0, /* tp_getset */\r | |
1431 | 0, /* tp_base */\r | |
1432 | 0, /* tp_dict */\r | |
1433 | property_descr_get, /* tp_descr_get */\r | |
1434 | property_descr_set, /* tp_descr_set */\r | |
1435 | 0, /* tp_dictoffset */\r | |
1436 | property_init, /* tp_init */\r | |
1437 | PyType_GenericAlloc, /* tp_alloc */\r | |
1438 | PyType_GenericNew, /* tp_new */\r | |
1439 | PyObject_GC_Del, /* tp_free */\r | |
1440 | };\r |