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