]>
Commit | Line | Data |
---|---|---|
4710c53d | 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 | PyObject *func, *result;\r | |
258 | \r | |
259 | func = PyCFunction_New(descr->d_method, (PyObject *)descr->d_type);\r | |
260 | if (func == NULL)\r | |
261 | return NULL;\r | |
262 | \r | |
263 | result = PyEval_CallObjectWithKeywords(func, args, kwds);\r | |
264 | Py_DECREF(func);\r | |
265 | return result;\r | |
266 | }\r | |
267 | \r | |
268 | static PyObject *\r | |
269 | wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds)\r | |
270 | {\r | |
271 | Py_ssize_t argc;\r | |
272 | PyObject *self, *func, *result;\r | |
273 | \r | |
274 | /* Make sure that the first argument is acceptable as 'self' */\r | |
275 | assert(PyTuple_Check(args));\r | |
276 | argc = PyTuple_GET_SIZE(args);\r | |
277 | if (argc < 1) {\r | |
278 | PyErr_Format(PyExc_TypeError,\r | |
279 | "descriptor '%.300s' of '%.100s' "\r | |
280 | "object needs an argument",\r | |
281 | descr_name((PyDescrObject *)descr),\r | |
282 | descr->d_type->tp_name);\r | |
283 | return NULL;\r | |
284 | }\r | |
285 | self = PyTuple_GET_ITEM(args, 0);\r | |
286 | if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),\r | |
287 | (PyObject *)(descr->d_type))) {\r | |
288 | PyErr_Format(PyExc_TypeError,\r | |
289 | "descriptor '%.200s' "\r | |
290 | "requires a '%.100s' object "\r | |
291 | "but received a '%.100s'",\r | |
292 | descr_name((PyDescrObject *)descr),\r | |
293 | descr->d_type->tp_name,\r | |
294 | self->ob_type->tp_name);\r | |
295 | return NULL;\r | |
296 | }\r | |
297 | \r | |
298 | func = PyWrapper_New((PyObject *)descr, self);\r | |
299 | if (func == NULL)\r | |
300 | return NULL;\r | |
301 | args = PyTuple_GetSlice(args, 1, argc);\r | |
302 | if (args == NULL) {\r | |
303 | Py_DECREF(func);\r | |
304 | return NULL;\r | |
305 | }\r | |
306 | result = PyEval_CallObjectWithKeywords(func, args, kwds);\r | |
307 | Py_DECREF(args);\r | |
308 | Py_DECREF(func);\r | |
309 | return result;\r | |
310 | }\r | |
311 | \r | |
312 | static PyObject *\r | |
313 | method_get_doc(PyMethodDescrObject *descr, void *closure)\r | |
314 | {\r | |
315 | if (descr->d_method->ml_doc == NULL) {\r | |
316 | Py_INCREF(Py_None);\r | |
317 | return Py_None;\r | |
318 | }\r | |
319 | return PyString_FromString(descr->d_method->ml_doc);\r | |
320 | }\r | |
321 | \r | |
322 | static PyMemberDef descr_members[] = {\r | |
323 | {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY},\r | |
324 | {"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY},\r | |
325 | {0}\r | |
326 | };\r | |
327 | \r | |
328 | static PyGetSetDef method_getset[] = {\r | |
329 | {"__doc__", (getter)method_get_doc},\r | |
330 | {0}\r | |
331 | };\r | |
332 | \r | |
333 | static PyObject *\r | |
334 | member_get_doc(PyMemberDescrObject *descr, void *closure)\r | |
335 | {\r | |
336 | if (descr->d_member->doc == NULL) {\r | |
337 | Py_INCREF(Py_None);\r | |
338 | return Py_None;\r | |
339 | }\r | |
340 | return PyString_FromString(descr->d_member->doc);\r | |
341 | }\r | |
342 | \r | |
343 | static PyGetSetDef member_getset[] = {\r | |
344 | {"__doc__", (getter)member_get_doc},\r | |
345 | {0}\r | |
346 | };\r | |
347 | \r | |
348 | static PyObject *\r | |
349 | getset_get_doc(PyGetSetDescrObject *descr, void *closure)\r | |
350 | {\r | |
351 | if (descr->d_getset->doc == NULL) {\r | |
352 | Py_INCREF(Py_None);\r | |
353 | return Py_None;\r | |
354 | }\r | |
355 | return PyString_FromString(descr->d_getset->doc);\r | |
356 | }\r | |
357 | \r | |
358 | static PyGetSetDef getset_getset[] = {\r | |
359 | {"__doc__", (getter)getset_get_doc},\r | |
360 | {0}\r | |
361 | };\r | |
362 | \r | |
363 | static PyObject *\r | |
364 | wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure)\r | |
365 | {\r | |
366 | if (descr->d_base->doc == NULL) {\r | |
367 | Py_INCREF(Py_None);\r | |
368 | return Py_None;\r | |
369 | }\r | |
370 | return PyString_FromString(descr->d_base->doc);\r | |
371 | }\r | |
372 | \r | |
373 | static PyGetSetDef wrapperdescr_getset[] = {\r | |
374 | {"__doc__", (getter)wrapperdescr_get_doc},\r | |
375 | {0}\r | |
376 | };\r | |
377 | \r | |
378 | static int\r | |
379 | descr_traverse(PyObject *self, visitproc visit, void *arg)\r | |
380 | {\r | |
381 | PyDescrObject *descr = (PyDescrObject *)self;\r | |
382 | Py_VISIT(descr->d_type);\r | |
383 | return 0;\r | |
384 | }\r | |
385 | \r | |
386 | static PyTypeObject PyMethodDescr_Type = {\r | |
387 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
388 | "method_descriptor",\r | |
389 | sizeof(PyMethodDescrObject),\r | |
390 | 0,\r | |
391 | (destructor)descr_dealloc, /* tp_dealloc */\r | |
392 | 0, /* tp_print */\r | |
393 | 0, /* tp_getattr */\r | |
394 | 0, /* tp_setattr */\r | |
395 | 0, /* tp_compare */\r | |
396 | (reprfunc)method_repr, /* tp_repr */\r | |
397 | 0, /* tp_as_number */\r | |
398 | 0, /* tp_as_sequence */\r | |
399 | 0, /* tp_as_mapping */\r | |
400 | 0, /* tp_hash */\r | |
401 | (ternaryfunc)methoddescr_call, /* tp_call */\r | |
402 | 0, /* tp_str */\r | |
403 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
404 | 0, /* tp_setattro */\r | |
405 | 0, /* tp_as_buffer */\r | |
406 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
407 | 0, /* tp_doc */\r | |
408 | descr_traverse, /* tp_traverse */\r | |
409 | 0, /* tp_clear */\r | |
410 | 0, /* tp_richcompare */\r | |
411 | 0, /* tp_weaklistoffset */\r | |
412 | 0, /* tp_iter */\r | |
413 | 0, /* tp_iternext */\r | |
414 | 0, /* tp_methods */\r | |
415 | descr_members, /* tp_members */\r | |
416 | method_getset, /* tp_getset */\r | |
417 | 0, /* tp_base */\r | |
418 | 0, /* tp_dict */\r | |
419 | (descrgetfunc)method_get, /* tp_descr_get */\r | |
420 | 0, /* tp_descr_set */\r | |
421 | };\r | |
422 | \r | |
423 | /* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */\r | |
424 | static PyTypeObject PyClassMethodDescr_Type = {\r | |
425 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
426 | "classmethod_descriptor",\r | |
427 | sizeof(PyMethodDescrObject),\r | |
428 | 0,\r | |
429 | (destructor)descr_dealloc, /* tp_dealloc */\r | |
430 | 0, /* tp_print */\r | |
431 | 0, /* tp_getattr */\r | |
432 | 0, /* tp_setattr */\r | |
433 | 0, /* tp_compare */\r | |
434 | (reprfunc)method_repr, /* tp_repr */\r | |
435 | 0, /* tp_as_number */\r | |
436 | 0, /* tp_as_sequence */\r | |
437 | 0, /* tp_as_mapping */\r | |
438 | 0, /* tp_hash */\r | |
439 | (ternaryfunc)classmethoddescr_call, /* tp_call */\r | |
440 | 0, /* tp_str */\r | |
441 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
442 | 0, /* tp_setattro */\r | |
443 | 0, /* tp_as_buffer */\r | |
444 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
445 | 0, /* tp_doc */\r | |
446 | descr_traverse, /* tp_traverse */\r | |
447 | 0, /* tp_clear */\r | |
448 | 0, /* tp_richcompare */\r | |
449 | 0, /* tp_weaklistoffset */\r | |
450 | 0, /* tp_iter */\r | |
451 | 0, /* tp_iternext */\r | |
452 | 0, /* tp_methods */\r | |
453 | descr_members, /* tp_members */\r | |
454 | method_getset, /* tp_getset */\r | |
455 | 0, /* tp_base */\r | |
456 | 0, /* tp_dict */\r | |
457 | (descrgetfunc)classmethod_get, /* tp_descr_get */\r | |
458 | 0, /* tp_descr_set */\r | |
459 | };\r | |
460 | \r | |
461 | PyTypeObject PyMemberDescr_Type = {\r | |
462 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
463 | "member_descriptor",\r | |
464 | sizeof(PyMemberDescrObject),\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)member_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 | 0, /* 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 | member_getset, /* tp_getset */\r | |
492 | 0, /* tp_base */\r | |
493 | 0, /* tp_dict */\r | |
494 | (descrgetfunc)member_get, /* tp_descr_get */\r | |
495 | (descrsetfunc)member_set, /* tp_descr_set */\r | |
496 | };\r | |
497 | \r | |
498 | PyTypeObject PyGetSetDescr_Type = {\r | |
499 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
500 | "getset_descriptor",\r | |
501 | sizeof(PyGetSetDescrObject),\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)getset_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 | getset_getset, /* tp_getset */\r | |
529 | 0, /* tp_base */\r | |
530 | 0, /* tp_dict */\r | |
531 | (descrgetfunc)getset_get, /* tp_descr_get */\r | |
532 | (descrsetfunc)getset_set, /* tp_descr_set */\r | |
533 | };\r | |
534 | \r | |
535 | PyTypeObject PyWrapperDescr_Type = {\r | |
536 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
537 | "wrapper_descriptor",\r | |
538 | sizeof(PyWrapperDescrObject),\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)wrapperdescr_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 | (ternaryfunc)wrapperdescr_call, /* 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 | wrapperdescr_getset, /* tp_getset */\r | |
566 | 0, /* tp_base */\r | |
567 | 0, /* tp_dict */\r | |
568 | (descrgetfunc)wrapperdescr_get, /* tp_descr_get */\r | |
569 | 0, /* tp_descr_set */\r | |
570 | };\r | |
571 | \r | |
572 | static PyDescrObject *\r | |
573 | descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)\r | |
574 | {\r | |
575 | PyDescrObject *descr;\r | |
576 | \r | |
577 | descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);\r | |
578 | if (descr != NULL) {\r | |
579 | Py_XINCREF(type);\r | |
580 | descr->d_type = type;\r | |
581 | descr->d_name = PyString_InternFromString(name);\r | |
582 | if (descr->d_name == NULL) {\r | |
583 | Py_DECREF(descr);\r | |
584 | descr = NULL;\r | |
585 | }\r | |
586 | }\r | |
587 | return descr;\r | |
588 | }\r | |
589 | \r | |
590 | PyObject *\r | |
591 | PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)\r | |
592 | {\r | |
593 | PyMethodDescrObject *descr;\r | |
594 | \r | |
595 | descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,\r | |
596 | type, method->ml_name);\r | |
597 | if (descr != NULL)\r | |
598 | descr->d_method = method;\r | |
599 | return (PyObject *)descr;\r | |
600 | }\r | |
601 | \r | |
602 | PyObject *\r | |
603 | PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)\r | |
604 | {\r | |
605 | PyMethodDescrObject *descr;\r | |
606 | \r | |
607 | descr = (PyMethodDescrObject *)descr_new(&PyClassMethodDescr_Type,\r | |
608 | type, method->ml_name);\r | |
609 | if (descr != NULL)\r | |
610 | descr->d_method = method;\r | |
611 | return (PyObject *)descr;\r | |
612 | }\r | |
613 | \r | |
614 | PyObject *\r | |
615 | PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member)\r | |
616 | {\r | |
617 | PyMemberDescrObject *descr;\r | |
618 | \r | |
619 | descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,\r | |
620 | type, member->name);\r | |
621 | if (descr != NULL)\r | |
622 | descr->d_member = member;\r | |
623 | return (PyObject *)descr;\r | |
624 | }\r | |
625 | \r | |
626 | PyObject *\r | |
627 | PyDescr_NewGetSet(PyTypeObject *type, PyGetSetDef *getset)\r | |
628 | {\r | |
629 | PyGetSetDescrObject *descr;\r | |
630 | \r | |
631 | descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,\r | |
632 | type, getset->name);\r | |
633 | if (descr != NULL)\r | |
634 | descr->d_getset = getset;\r | |
635 | return (PyObject *)descr;\r | |
636 | }\r | |
637 | \r | |
638 | PyObject *\r | |
639 | PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)\r | |
640 | {\r | |
641 | PyWrapperDescrObject *descr;\r | |
642 | \r | |
643 | descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,\r | |
644 | type, base->name);\r | |
645 | if (descr != NULL) {\r | |
646 | descr->d_base = base;\r | |
647 | descr->d_wrapped = wrapped;\r | |
648 | }\r | |
649 | return (PyObject *)descr;\r | |
650 | }\r | |
651 | \r | |
652 | \r | |
653 | /* --- Readonly proxy for dictionaries (actually any mapping) --- */\r | |
654 | \r | |
655 | /* This has no reason to be in this file except that adding new files is a\r | |
656 | bit of a pain */\r | |
657 | \r | |
658 | typedef struct {\r | |
659 | PyObject_HEAD\r | |
660 | PyObject *dict;\r | |
661 | } proxyobject;\r | |
662 | \r | |
663 | static Py_ssize_t\r | |
664 | proxy_len(proxyobject *pp)\r | |
665 | {\r | |
666 | return PyObject_Size(pp->dict);\r | |
667 | }\r | |
668 | \r | |
669 | static PyObject *\r | |
670 | proxy_getitem(proxyobject *pp, PyObject *key)\r | |
671 | {\r | |
672 | return PyObject_GetItem(pp->dict, key);\r | |
673 | }\r | |
674 | \r | |
675 | static PyMappingMethods proxy_as_mapping = {\r | |
676 | (lenfunc)proxy_len, /* mp_length */\r | |
677 | (binaryfunc)proxy_getitem, /* mp_subscript */\r | |
678 | 0, /* mp_ass_subscript */\r | |
679 | };\r | |
680 | \r | |
681 | static int\r | |
682 | proxy_contains(proxyobject *pp, PyObject *key)\r | |
683 | {\r | |
684 | return PyDict_Contains(pp->dict, key);\r | |
685 | }\r | |
686 | \r | |
687 | static PySequenceMethods proxy_as_sequence = {\r | |
688 | 0, /* sq_length */\r | |
689 | 0, /* sq_concat */\r | |
690 | 0, /* sq_repeat */\r | |
691 | 0, /* sq_item */\r | |
692 | 0, /* sq_slice */\r | |
693 | 0, /* sq_ass_item */\r | |
694 | 0, /* sq_ass_slice */\r | |
695 | (objobjproc)proxy_contains, /* sq_contains */\r | |
696 | 0, /* sq_inplace_concat */\r | |
697 | 0, /* sq_inplace_repeat */\r | |
698 | };\r | |
699 | \r | |
700 | static PyObject *\r | |
701 | proxy_has_key(proxyobject *pp, PyObject *key)\r | |
702 | {\r | |
703 | int res = PyDict_Contains(pp->dict, key);\r | |
704 | if (res < 0)\r | |
705 | return NULL;\r | |
706 | return PyBool_FromLong(res);\r | |
707 | }\r | |
708 | \r | |
709 | static PyObject *\r | |
710 | proxy_get(proxyobject *pp, PyObject *args)\r | |
711 | {\r | |
712 | PyObject *key, *def = Py_None;\r | |
713 | \r | |
714 | if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def))\r | |
715 | return NULL;\r | |
716 | return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def);\r | |
717 | }\r | |
718 | \r | |
719 | static PyObject *\r | |
720 | proxy_keys(proxyobject *pp)\r | |
721 | {\r | |
722 | return PyMapping_Keys(pp->dict);\r | |
723 | }\r | |
724 | \r | |
725 | static PyObject *\r | |
726 | proxy_values(proxyobject *pp)\r | |
727 | {\r | |
728 | return PyMapping_Values(pp->dict);\r | |
729 | }\r | |
730 | \r | |
731 | static PyObject *\r | |
732 | proxy_items(proxyobject *pp)\r | |
733 | {\r | |
734 | return PyMapping_Items(pp->dict);\r | |
735 | }\r | |
736 | \r | |
737 | static PyObject *\r | |
738 | proxy_iterkeys(proxyobject *pp)\r | |
739 | {\r | |
740 | return PyObject_CallMethod(pp->dict, "iterkeys", NULL);\r | |
741 | }\r | |
742 | \r | |
743 | static PyObject *\r | |
744 | proxy_itervalues(proxyobject *pp)\r | |
745 | {\r | |
746 | return PyObject_CallMethod(pp->dict, "itervalues", NULL);\r | |
747 | }\r | |
748 | \r | |
749 | static PyObject *\r | |
750 | proxy_iteritems(proxyobject *pp)\r | |
751 | {\r | |
752 | return PyObject_CallMethod(pp->dict, "iteritems", NULL);\r | |
753 | }\r | |
754 | static PyObject *\r | |
755 | proxy_copy(proxyobject *pp)\r | |
756 | {\r | |
757 | return PyObject_CallMethod(pp->dict, "copy", NULL);\r | |
758 | }\r | |
759 | \r | |
760 | static PyMethodDef proxy_methods[] = {\r | |
761 | {"has_key", (PyCFunction)proxy_has_key, METH_O,\r | |
762 | PyDoc_STR("D.has_key(k) -> True if D has a key k, else False")},\r | |
763 | {"get", (PyCFunction)proxy_get, METH_VARARGS,\r | |
764 | PyDoc_STR("D.get(k[,d]) -> D[k] if D.has_key(k), else d."\r | |
765 | " d defaults to None.")},\r | |
766 | {"keys", (PyCFunction)proxy_keys, METH_NOARGS,\r | |
767 | PyDoc_STR("D.keys() -> list of D's keys")},\r | |
768 | {"values", (PyCFunction)proxy_values, METH_NOARGS,\r | |
769 | PyDoc_STR("D.values() -> list of D's values")},\r | |
770 | {"items", (PyCFunction)proxy_items, METH_NOARGS,\r | |
771 | PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")},\r | |
772 | {"iterkeys", (PyCFunction)proxy_iterkeys, METH_NOARGS,\r | |
773 | PyDoc_STR("D.iterkeys() -> an iterator over the keys of D")},\r | |
774 | {"itervalues",(PyCFunction)proxy_itervalues, METH_NOARGS,\r | |
775 | PyDoc_STR("D.itervalues() -> an iterator over the values of D")},\r | |
776 | {"iteritems", (PyCFunction)proxy_iteritems, METH_NOARGS,\r | |
777 | PyDoc_STR("D.iteritems() ->"\r | |
778 | " an iterator over the (key, value) items of D")},\r | |
779 | {"copy", (PyCFunction)proxy_copy, METH_NOARGS,\r | |
780 | PyDoc_STR("D.copy() -> a shallow copy of D")},\r | |
781 | {0}\r | |
782 | };\r | |
783 | \r | |
784 | static void\r | |
785 | proxy_dealloc(proxyobject *pp)\r | |
786 | {\r | |
787 | _PyObject_GC_UNTRACK(pp);\r | |
788 | Py_DECREF(pp->dict);\r | |
789 | PyObject_GC_Del(pp);\r | |
790 | }\r | |
791 | \r | |
792 | static PyObject *\r | |
793 | proxy_getiter(proxyobject *pp)\r | |
794 | {\r | |
795 | return PyObject_GetIter(pp->dict);\r | |
796 | }\r | |
797 | \r | |
798 | static PyObject *\r | |
799 | proxy_str(proxyobject *pp)\r | |
800 | {\r | |
801 | return PyObject_Str(pp->dict);\r | |
802 | }\r | |
803 | \r | |
804 | static int\r | |
805 | proxy_traverse(PyObject *self, visitproc visit, void *arg)\r | |
806 | {\r | |
807 | proxyobject *pp = (proxyobject *)self;\r | |
808 | Py_VISIT(pp->dict);\r | |
809 | return 0;\r | |
810 | }\r | |
811 | \r | |
812 | static int\r | |
813 | proxy_compare(proxyobject *v, PyObject *w)\r | |
814 | {\r | |
815 | return PyObject_Compare(v->dict, w);\r | |
816 | }\r | |
817 | \r | |
818 | static PyObject *\r | |
819 | proxy_richcompare(proxyobject *v, PyObject *w, int op)\r | |
820 | {\r | |
821 | return PyObject_RichCompare(v->dict, w, op);\r | |
822 | }\r | |
823 | \r | |
824 | PyTypeObject PyDictProxy_Type = {\r | |
825 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
826 | "dictproxy", /* tp_name */\r | |
827 | sizeof(proxyobject), /* tp_basicsize */\r | |
828 | 0, /* tp_itemsize */\r | |
829 | /* methods */\r | |
830 | (destructor)proxy_dealloc, /* tp_dealloc */\r | |
831 | 0, /* tp_print */\r | |
832 | 0, /* tp_getattr */\r | |
833 | 0, /* tp_setattr */\r | |
834 | (cmpfunc)proxy_compare, /* tp_compare */\r | |
835 | 0, /* tp_repr */\r | |
836 | 0, /* tp_as_number */\r | |
837 | &proxy_as_sequence, /* tp_as_sequence */\r | |
838 | &proxy_as_mapping, /* tp_as_mapping */\r | |
839 | 0, /* tp_hash */\r | |
840 | 0, /* tp_call */\r | |
841 | (reprfunc)proxy_str, /* tp_str */\r | |
842 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
843 | 0, /* tp_setattro */\r | |
844 | 0, /* tp_as_buffer */\r | |
845 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
846 | 0, /* tp_doc */\r | |
847 | proxy_traverse, /* tp_traverse */\r | |
848 | 0, /* tp_clear */\r | |
849 | (richcmpfunc)proxy_richcompare, /* tp_richcompare */\r | |
850 | 0, /* tp_weaklistoffset */\r | |
851 | (getiterfunc)proxy_getiter, /* tp_iter */\r | |
852 | 0, /* tp_iternext */\r | |
853 | proxy_methods, /* tp_methods */\r | |
854 | 0, /* tp_members */\r | |
855 | 0, /* tp_getset */\r | |
856 | 0, /* tp_base */\r | |
857 | 0, /* tp_dict */\r | |
858 | 0, /* tp_descr_get */\r | |
859 | 0, /* tp_descr_set */\r | |
860 | };\r | |
861 | \r | |
862 | PyObject *\r | |
863 | PyDictProxy_New(PyObject *dict)\r | |
864 | {\r | |
865 | proxyobject *pp;\r | |
866 | \r | |
867 | pp = PyObject_GC_New(proxyobject, &PyDictProxy_Type);\r | |
868 | if (pp != NULL) {\r | |
869 | Py_INCREF(dict);\r | |
870 | pp->dict = dict;\r | |
871 | _PyObject_GC_TRACK(pp);\r | |
872 | }\r | |
873 | return (PyObject *)pp;\r | |
874 | }\r | |
875 | \r | |
876 | \r | |
877 | /* --- Wrapper object for "slot" methods --- */\r | |
878 | \r | |
879 | /* This has no reason to be in this file except that adding new files is a\r | |
880 | bit of a pain */\r | |
881 | \r | |
882 | typedef struct {\r | |
883 | PyObject_HEAD\r | |
884 | PyWrapperDescrObject *descr;\r | |
885 | PyObject *self;\r | |
886 | } wrapperobject;\r | |
887 | \r | |
888 | static void\r | |
889 | wrapper_dealloc(wrapperobject *wp)\r | |
890 | {\r | |
891 | PyObject_GC_UnTrack(wp);\r | |
892 | Py_TRASHCAN_SAFE_BEGIN(wp)\r | |
893 | Py_XDECREF(wp->descr);\r | |
894 | Py_XDECREF(wp->self);\r | |
895 | PyObject_GC_Del(wp);\r | |
896 | Py_TRASHCAN_SAFE_END(wp)\r | |
897 | }\r | |
898 | \r | |
899 | static int\r | |
900 | wrapper_compare(wrapperobject *a, wrapperobject *b)\r | |
901 | {\r | |
902 | if (a->descr == b->descr)\r | |
903 | return PyObject_Compare(a->self, b->self);\r | |
904 | else\r | |
905 | return (a->descr < b->descr) ? -1 : 1;\r | |
906 | }\r | |
907 | \r | |
908 | static long\r | |
909 | wrapper_hash(wrapperobject *wp)\r | |
910 | {\r | |
911 | int x, y;\r | |
912 | x = _Py_HashPointer(wp->descr);\r | |
913 | if (x == -1)\r | |
914 | return -1;\r | |
915 | y = PyObject_Hash(wp->self);\r | |
916 | if (y == -1)\r | |
917 | return -1;\r | |
918 | x = x ^ y;\r | |
919 | if (x == -1)\r | |
920 | x = -2;\r | |
921 | return x;\r | |
922 | }\r | |
923 | \r | |
924 | static PyObject *\r | |
925 | wrapper_repr(wrapperobject *wp)\r | |
926 | {\r | |
927 | return PyString_FromFormat("<method-wrapper '%s' of %s object at %p>",\r | |
928 | wp->descr->d_base->name,\r | |
929 | wp->self->ob_type->tp_name,\r | |
930 | wp->self);\r | |
931 | }\r | |
932 | \r | |
933 | static PyMemberDef wrapper_members[] = {\r | |
934 | {"__self__", T_OBJECT, offsetof(wrapperobject, self), READONLY},\r | |
935 | {0}\r | |
936 | };\r | |
937 | \r | |
938 | static PyObject *\r | |
939 | wrapper_objclass(wrapperobject *wp)\r | |
940 | {\r | |
941 | PyObject *c = (PyObject *)wp->descr->d_type;\r | |
942 | \r | |
943 | Py_INCREF(c);\r | |
944 | return c;\r | |
945 | }\r | |
946 | \r | |
947 | static PyObject *\r | |
948 | wrapper_name(wrapperobject *wp)\r | |
949 | {\r | |
950 | char *s = wp->descr->d_base->name;\r | |
951 | \r | |
952 | return PyString_FromString(s);\r | |
953 | }\r | |
954 | \r | |
955 | static PyObject *\r | |
956 | wrapper_doc(wrapperobject *wp)\r | |
957 | {\r | |
958 | char *s = wp->descr->d_base->doc;\r | |
959 | \r | |
960 | if (s == NULL) {\r | |
961 | Py_INCREF(Py_None);\r | |
962 | return Py_None;\r | |
963 | }\r | |
964 | else {\r | |
965 | return PyString_FromString(s);\r | |
966 | }\r | |
967 | }\r | |
968 | \r | |
969 | static PyGetSetDef wrapper_getsets[] = {\r | |
970 | {"__objclass__", (getter)wrapper_objclass},\r | |
971 | {"__name__", (getter)wrapper_name},\r | |
972 | {"__doc__", (getter)wrapper_doc},\r | |
973 | {0}\r | |
974 | };\r | |
975 | \r | |
976 | static PyObject *\r | |
977 | wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)\r | |
978 | {\r | |
979 | wrapperfunc wrapper = wp->descr->d_base->wrapper;\r | |
980 | PyObject *self = wp->self;\r | |
981 | \r | |
982 | if (wp->descr->d_base->flags & PyWrapperFlag_KEYWORDS) {\r | |
983 | wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper;\r | |
984 | return (*wk)(self, args, wp->descr->d_wrapped, kwds);\r | |
985 | }\r | |
986 | \r | |
987 | if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) {\r | |
988 | PyErr_Format(PyExc_TypeError,\r | |
989 | "wrapper %s doesn't take keyword arguments",\r | |
990 | wp->descr->d_base->name);\r | |
991 | return NULL;\r | |
992 | }\r | |
993 | return (*wrapper)(self, args, wp->descr->d_wrapped);\r | |
994 | }\r | |
995 | \r | |
996 | static int\r | |
997 | wrapper_traverse(PyObject *self, visitproc visit, void *arg)\r | |
998 | {\r | |
999 | wrapperobject *wp = (wrapperobject *)self;\r | |
1000 | Py_VISIT(wp->descr);\r | |
1001 | Py_VISIT(wp->self);\r | |
1002 | return 0;\r | |
1003 | }\r | |
1004 | \r | |
1005 | static PyTypeObject wrappertype = {\r | |
1006 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
1007 | "method-wrapper", /* tp_name */\r | |
1008 | sizeof(wrapperobject), /* tp_basicsize */\r | |
1009 | 0, /* tp_itemsize */\r | |
1010 | /* methods */\r | |
1011 | (destructor)wrapper_dealloc, /* tp_dealloc */\r | |
1012 | 0, /* tp_print */\r | |
1013 | 0, /* tp_getattr */\r | |
1014 | 0, /* tp_setattr */\r | |
1015 | (cmpfunc)wrapper_compare, /* tp_compare */\r | |
1016 | (reprfunc)wrapper_repr, /* tp_repr */\r | |
1017 | 0, /* tp_as_number */\r | |
1018 | 0, /* tp_as_sequence */\r | |
1019 | 0, /* tp_as_mapping */\r | |
1020 | (hashfunc)wrapper_hash, /* tp_hash */\r | |
1021 | (ternaryfunc)wrapper_call, /* tp_call */\r | |
1022 | 0, /* tp_str */\r | |
1023 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
1024 | 0, /* tp_setattro */\r | |
1025 | 0, /* tp_as_buffer */\r | |
1026 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r | |
1027 | 0, /* tp_doc */\r | |
1028 | wrapper_traverse, /* tp_traverse */\r | |
1029 | 0, /* tp_clear */\r | |
1030 | 0, /* tp_richcompare */\r | |
1031 | 0, /* tp_weaklistoffset */\r | |
1032 | 0, /* tp_iter */\r | |
1033 | 0, /* tp_iternext */\r | |
1034 | 0, /* tp_methods */\r | |
1035 | wrapper_members, /* tp_members */\r | |
1036 | wrapper_getsets, /* tp_getset */\r | |
1037 | 0, /* tp_base */\r | |
1038 | 0, /* tp_dict */\r | |
1039 | 0, /* tp_descr_get */\r | |
1040 | 0, /* tp_descr_set */\r | |
1041 | };\r | |
1042 | \r | |
1043 | PyObject *\r | |
1044 | PyWrapper_New(PyObject *d, PyObject *self)\r | |
1045 | {\r | |
1046 | wrapperobject *wp;\r | |
1047 | PyWrapperDescrObject *descr;\r | |
1048 | \r | |
1049 | assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));\r | |
1050 | descr = (PyWrapperDescrObject *)d;\r | |
1051 | assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),\r | |
1052 | (PyObject *)(descr->d_type)));\r | |
1053 | \r | |
1054 | wp = PyObject_GC_New(wrapperobject, &wrappertype);\r | |
1055 | if (wp != NULL) {\r | |
1056 | Py_INCREF(descr);\r | |
1057 | wp->descr = descr;\r | |
1058 | Py_INCREF(self);\r | |
1059 | wp->self = self;\r | |
1060 | _PyObject_GC_TRACK(wp);\r | |
1061 | }\r | |
1062 | return (PyObject *)wp;\r | |
1063 | }\r | |
1064 | \r | |
1065 | \r | |
1066 | /* A built-in 'property' type */\r | |
1067 | \r | |
1068 | /*\r | |
1069 | class property(object):\r | |
1070 | \r | |
1071 | def __init__(self, fget=None, fset=None, fdel=None, doc=None):\r | |
1072 | if doc is None and fget is not None and hasattr(fget, "__doc__"):\r | |
1073 | doc = fget.__doc__\r | |
1074 | self.__get = fget\r | |
1075 | self.__set = fset\r | |
1076 | self.__del = fdel\r | |
1077 | self.__doc__ = doc\r | |
1078 | \r | |
1079 | def __get__(self, inst, type=None):\r | |
1080 | if inst is None:\r | |
1081 | return self\r | |
1082 | if self.__get is None:\r | |
1083 | raise AttributeError, "unreadable attribute"\r | |
1084 | return self.__get(inst)\r | |
1085 | \r | |
1086 | def __set__(self, inst, value):\r | |
1087 | if self.__set is None:\r | |
1088 | raise AttributeError, "can't set attribute"\r | |
1089 | return self.__set(inst, value)\r | |
1090 | \r | |
1091 | def __delete__(self, inst):\r | |
1092 | if self.__del is None:\r | |
1093 | raise AttributeError, "can't delete attribute"\r | |
1094 | return self.__del(inst)\r | |
1095 | \r | |
1096 | */\r | |
1097 | \r | |
1098 | typedef struct {\r | |
1099 | PyObject_HEAD\r | |
1100 | PyObject *prop_get;\r | |
1101 | PyObject *prop_set;\r | |
1102 | PyObject *prop_del;\r | |
1103 | PyObject *prop_doc;\r | |
1104 | int getter_doc;\r | |
1105 | } propertyobject;\r | |
1106 | \r | |
1107 | static PyObject * property_copy(PyObject *, PyObject *, PyObject *,\r | |
1108 | PyObject *);\r | |
1109 | \r | |
1110 | static PyMemberDef property_members[] = {\r | |
1111 | {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY},\r | |
1112 | {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY},\r | |
1113 | {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY},\r | |
1114 | {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY},\r | |
1115 | {0}\r | |
1116 | };\r | |
1117 | \r | |
1118 | \r | |
1119 | PyDoc_STRVAR(getter_doc,\r | |
1120 | "Descriptor to change the getter on a property.");\r | |
1121 | \r | |
1122 | static PyObject *\r | |
1123 | property_getter(PyObject *self, PyObject *getter)\r | |
1124 | {\r | |
1125 | return property_copy(self, getter, NULL, NULL);\r | |
1126 | }\r | |
1127 | \r | |
1128 | \r | |
1129 | PyDoc_STRVAR(setter_doc,\r | |
1130 | "Descriptor to change the setter on a property.");\r | |
1131 | \r | |
1132 | static PyObject *\r | |
1133 | property_setter(PyObject *self, PyObject *setter)\r | |
1134 | {\r | |
1135 | return property_copy(self, NULL, setter, NULL);\r | |
1136 | }\r | |
1137 | \r | |
1138 | \r | |
1139 | PyDoc_STRVAR(deleter_doc,\r | |
1140 | "Descriptor to change the deleter on a property.");\r | |
1141 | \r | |
1142 | static PyObject *\r | |
1143 | property_deleter(PyObject *self, PyObject *deleter)\r | |
1144 | {\r | |
1145 | return property_copy(self, NULL, NULL, deleter);\r | |
1146 | }\r | |
1147 | \r | |
1148 | \r | |
1149 | static PyMethodDef property_methods[] = {\r | |
1150 | {"getter", property_getter, METH_O, getter_doc},\r | |
1151 | {"setter", property_setter, METH_O, setter_doc},\r | |
1152 | {"deleter", property_deleter, METH_O, deleter_doc},\r | |
1153 | {0}\r | |
1154 | };\r | |
1155 | \r | |
1156 | \r | |
1157 | static void\r | |
1158 | property_dealloc(PyObject *self)\r | |
1159 | {\r | |
1160 | propertyobject *gs = (propertyobject *)self;\r | |
1161 | \r | |
1162 | _PyObject_GC_UNTRACK(self);\r | |
1163 | Py_XDECREF(gs->prop_get);\r | |
1164 | Py_XDECREF(gs->prop_set);\r | |
1165 | Py_XDECREF(gs->prop_del);\r | |
1166 | Py_XDECREF(gs->prop_doc);\r | |
1167 | self->ob_type->tp_free(self);\r | |
1168 | }\r | |
1169 | \r | |
1170 | static PyObject *\r | |
1171 | property_descr_get(PyObject *self, PyObject *obj, PyObject *type)\r | |
1172 | {\r | |
1173 | propertyobject *gs = (propertyobject *)self;\r | |
1174 | \r | |
1175 | if (obj == NULL || obj == Py_None) {\r | |
1176 | Py_INCREF(self);\r | |
1177 | return self;\r | |
1178 | }\r | |
1179 | if (gs->prop_get == NULL) {\r | |
1180 | PyErr_SetString(PyExc_AttributeError, "unreadable attribute");\r | |
1181 | return NULL;\r | |
1182 | }\r | |
1183 | return PyObject_CallFunction(gs->prop_get, "(O)", obj);\r | |
1184 | }\r | |
1185 | \r | |
1186 | static int\r | |
1187 | property_descr_set(PyObject *self, PyObject *obj, PyObject *value)\r | |
1188 | {\r | |
1189 | propertyobject *gs = (propertyobject *)self;\r | |
1190 | PyObject *func, *res;\r | |
1191 | \r | |
1192 | if (value == NULL)\r | |
1193 | func = gs->prop_del;\r | |
1194 | else\r | |
1195 | func = gs->prop_set;\r | |
1196 | if (func == NULL) {\r | |
1197 | PyErr_SetString(PyExc_AttributeError,\r | |
1198 | value == NULL ?\r | |
1199 | "can't delete attribute" :\r | |
1200 | "can't set attribute");\r | |
1201 | return -1;\r | |
1202 | }\r | |
1203 | if (value == NULL)\r | |
1204 | res = PyObject_CallFunction(func, "(O)", obj);\r | |
1205 | else\r | |
1206 | res = PyObject_CallFunction(func, "(OO)", obj, value);\r | |
1207 | if (res == NULL)\r | |
1208 | return -1;\r | |
1209 | Py_DECREF(res);\r | |
1210 | return 0;\r | |
1211 | }\r | |
1212 | \r | |
1213 | static PyObject *\r | |
1214 | property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *del)\r | |
1215 | {\r | |
1216 | propertyobject *pold = (propertyobject *)old;\r | |
1217 | PyObject *new, *type, *doc;\r | |
1218 | \r | |
1219 | type = PyObject_Type(old);\r | |
1220 | if (type == NULL)\r | |
1221 | return NULL;\r | |
1222 | \r | |
1223 | if (get == NULL || get == Py_None) {\r | |
1224 | Py_XDECREF(get);\r | |
1225 | get = pold->prop_get ? pold->prop_get : Py_None;\r | |
1226 | }\r | |
1227 | if (set == NULL || set == Py_None) {\r | |
1228 | Py_XDECREF(set);\r | |
1229 | set = pold->prop_set ? pold->prop_set : Py_None;\r | |
1230 | }\r | |
1231 | if (del == NULL || del == Py_None) {\r | |
1232 | Py_XDECREF(del);\r | |
1233 | del = pold->prop_del ? pold->prop_del : Py_None;\r | |
1234 | }\r | |
1235 | if (pold->getter_doc && get != Py_None) {\r | |
1236 | /* make _init use __doc__ from getter */\r | |
1237 | doc = Py_None;\r | |
1238 | }\r | |
1239 | else {\r | |
1240 | doc = pold->prop_doc ? pold->prop_doc : Py_None;\r | |
1241 | }\r | |
1242 | \r | |
1243 | new = PyObject_CallFunction(type, "OOOO", get, set, del, doc);\r | |
1244 | Py_DECREF(type);\r | |
1245 | if (new == NULL)\r | |
1246 | return NULL;\r | |
1247 | return new;\r | |
1248 | }\r | |
1249 | \r | |
1250 | static int\r | |
1251 | property_init(PyObject *self, PyObject *args, PyObject *kwds)\r | |
1252 | {\r | |
1253 | PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL;\r | |
1254 | static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0};\r | |
1255 | propertyobject *prop = (propertyobject *)self;\r | |
1256 | \r | |
1257 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property",\r | |
1258 | kwlist, &get, &set, &del, &doc))\r | |
1259 | return -1;\r | |
1260 | \r | |
1261 | if (get == Py_None)\r | |
1262 | get = NULL;\r | |
1263 | if (set == Py_None)\r | |
1264 | set = NULL;\r | |
1265 | if (del == Py_None)\r | |
1266 | del = NULL;\r | |
1267 | \r | |
1268 | Py_XINCREF(get);\r | |
1269 | Py_XINCREF(set);\r | |
1270 | Py_XINCREF(del);\r | |
1271 | Py_XINCREF(doc);\r | |
1272 | \r | |
1273 | prop->prop_get = get;\r | |
1274 | prop->prop_set = set;\r | |
1275 | prop->prop_del = del;\r | |
1276 | prop->prop_doc = doc;\r | |
1277 | prop->getter_doc = 0;\r | |
1278 | \r | |
1279 | /* if no docstring given and the getter has one, use that one */\r | |
1280 | if ((doc == NULL || doc == Py_None) && get != NULL) {\r | |
1281 | PyObject *get_doc = PyObject_GetAttrString(get, "__doc__");\r | |
1282 | if (get_doc) {\r | |
1283 | if (Py_TYPE(self) == &PyProperty_Type) {\r | |
1284 | Py_XDECREF(prop->prop_doc);\r | |
1285 | prop->prop_doc = get_doc;\r | |
1286 | }\r | |
1287 | else {\r | |
1288 | /* If this is a property subclass, put __doc__\r | |
1289 | in dict of the subclass instance instead,\r | |
1290 | otherwise it gets shadowed by __doc__ in the\r | |
1291 | class's dict. */\r | |
1292 | int err = PyObject_SetAttrString(self, "__doc__", get_doc);\r | |
1293 | Py_DECREF(get_doc);\r | |
1294 | if (err < 0)\r | |
1295 | return -1;\r | |
1296 | }\r | |
1297 | prop->getter_doc = 1;\r | |
1298 | }\r | |
1299 | else if (PyErr_ExceptionMatches(PyExc_Exception)) {\r | |
1300 | PyErr_Clear();\r | |
1301 | }\r | |
1302 | else {\r | |
1303 | return -1;\r | |
1304 | }\r | |
1305 | }\r | |
1306 | \r | |
1307 | return 0;\r | |
1308 | }\r | |
1309 | \r | |
1310 | PyDoc_STRVAR(property_doc,\r | |
1311 | "property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n"\r | |
1312 | "\n"\r | |
1313 | "fget is a function to be used for getting an attribute value, and likewise\n"\r | |
1314 | "fset is a function for setting, and fdel a function for del'ing, an\n"\r | |
1315 | "attribute. Typical use is to define a managed attribute x:\n"\r | |
1316 | "class C(object):\n"\r | |
1317 | " def getx(self): return self._x\n"\r | |
1318 | " def setx(self, value): self._x = value\n"\r | |
1319 | " def delx(self): del self._x\n"\r | |
1320 | " x = property(getx, setx, delx, \"I'm the 'x' property.\")\n"\r | |
1321 | "\n"\r | |
1322 | "Decorators make defining new properties or modifying existing ones easy:\n"\r | |
1323 | "class C(object):\n"\r | |
1324 | " @property\n"\r | |
1325 | " def x(self): return self._x\n"\r | |
1326 | " @x.setter\n"\r | |
1327 | " def x(self, value): self._x = value\n"\r | |
1328 | " @x.deleter\n"\r | |
1329 | " def x(self): del self._x\n"\r | |
1330 | );\r | |
1331 | \r | |
1332 | static int\r | |
1333 | property_traverse(PyObject *self, visitproc visit, void *arg)\r | |
1334 | {\r | |
1335 | propertyobject *pp = (propertyobject *)self;\r | |
1336 | Py_VISIT(pp->prop_get);\r | |
1337 | Py_VISIT(pp->prop_set);\r | |
1338 | Py_VISIT(pp->prop_del);\r | |
1339 | Py_VISIT(pp->prop_doc);\r | |
1340 | return 0;\r | |
1341 | }\r | |
1342 | \r | |
1343 | PyTypeObject PyProperty_Type = {\r | |
1344 | PyVarObject_HEAD_INIT(&PyType_Type, 0)\r | |
1345 | "property", /* tp_name */\r | |
1346 | sizeof(propertyobject), /* tp_basicsize */\r | |
1347 | 0, /* tp_itemsize */\r | |
1348 | /* methods */\r | |
1349 | property_dealloc, /* tp_dealloc */\r | |
1350 | 0, /* tp_print */\r | |
1351 | 0, /* tp_getattr */\r | |
1352 | 0, /* tp_setattr */\r | |
1353 | 0, /* tp_compare */\r | |
1354 | 0, /* tp_repr */\r | |
1355 | 0, /* tp_as_number */\r | |
1356 | 0, /* tp_as_sequence */\r | |
1357 | 0, /* tp_as_mapping */\r | |
1358 | 0, /* tp_hash */\r | |
1359 | 0, /* tp_call */\r | |
1360 | 0, /* tp_str */\r | |
1361 | PyObject_GenericGetAttr, /* tp_getattro */\r | |
1362 | 0, /* tp_setattro */\r | |
1363 | 0, /* tp_as_buffer */\r | |
1364 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |\r | |
1365 | Py_TPFLAGS_BASETYPE, /* tp_flags */\r | |
1366 | property_doc, /* tp_doc */\r | |
1367 | property_traverse, /* tp_traverse */\r | |
1368 | 0, /* tp_clear */\r | |
1369 | 0, /* tp_richcompare */\r | |
1370 | 0, /* tp_weaklistoffset */\r | |
1371 | 0, /* tp_iter */\r | |
1372 | 0, /* tp_iternext */\r | |
1373 | property_methods, /* tp_methods */\r | |
1374 | property_members, /* tp_members */\r | |
1375 | 0, /* tp_getset */\r | |
1376 | 0, /* tp_base */\r | |
1377 | 0, /* tp_dict */\r | |
1378 | property_descr_get, /* tp_descr_get */\r | |
1379 | property_descr_set, /* tp_descr_set */\r | |
1380 | 0, /* tp_dictoffset */\r | |
1381 | property_init, /* tp_init */\r | |
1382 | PyType_GenericAlloc, /* tp_alloc */\r | |
1383 | PyType_GenericNew, /* tp_new */\r | |
1384 | PyObject_GC_Del, /* tp_free */\r | |
1385 | };\r |