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