• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Descriptors -- a new, flexible way to describe attributes */
2 
3 #include "Python.h"
4 #include "pycore_abstract.h"      // _PyObject_RealIsSubclass()
5 #include "pycore_call.h"          // _PyStack_AsDict()
6 #include "pycore_ceval.h"         // _Py_EnterRecursiveCallTstate()
7 #include "pycore_emscripten_trampoline.h" // descr_set_trampoline_call(), descr_get_trampoline_call()
8 #include "pycore_descrobject.h"   // _PyMethodWrapper_Type
9 #include "pycore_modsupport.h"    // _PyArg_UnpackStack()
10 #include "pycore_object.h"        // _PyObject_GC_UNTRACK()
11 #include "pycore_pystate.h"       // _PyThreadState_GET()
12 #include "pycore_tuple.h"         // _PyTuple_ITEMS()
13 
14 
15 /*[clinic input]
16 class mappingproxy "mappingproxyobject *" "&PyDictProxy_Type"
17 class property "propertyobject *" "&PyProperty_Type"
18 [clinic start generated code]*/
19 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=556352653fd4c02e]*/
20 
21 static void
descr_dealloc(PyObject * self)22 descr_dealloc(PyObject *self)
23 {
24     PyDescrObject *descr = (PyDescrObject *)self;
25     _PyObject_GC_UNTRACK(descr);
26     Py_XDECREF(descr->d_type);
27     Py_XDECREF(descr->d_name);
28     Py_XDECREF(descr->d_qualname);
29     PyObject_GC_Del(descr);
30 }
31 
32 static PyObject *
descr_name(PyDescrObject * descr)33 descr_name(PyDescrObject *descr)
34 {
35     if (descr->d_name != NULL && PyUnicode_Check(descr->d_name))
36         return descr->d_name;
37     return NULL;
38 }
39 
40 static PyObject *
descr_repr(PyDescrObject * descr,const char * format)41 descr_repr(PyDescrObject *descr, const char *format)
42 {
43     PyObject *name = NULL;
44     if (descr->d_name != NULL && PyUnicode_Check(descr->d_name))
45         name = descr->d_name;
46 
47     return PyUnicode_FromFormat(format, name, "?", descr->d_type->tp_name);
48 }
49 
50 static PyObject *
method_repr(PyObject * descr)51 method_repr(PyObject *descr)
52 {
53     return descr_repr((PyDescrObject *)descr,
54                       "<method '%V' of '%s' objects>");
55 }
56 
57 static PyObject *
member_repr(PyObject * descr)58 member_repr(PyObject *descr)
59 {
60     return descr_repr((PyDescrObject *)descr,
61                       "<member '%V' of '%s' objects>");
62 }
63 
64 static PyObject *
getset_repr(PyObject * descr)65 getset_repr(PyObject *descr)
66 {
67     return descr_repr((PyDescrObject *)descr,
68                       "<attribute '%V' of '%s' objects>");
69 }
70 
71 static PyObject *
wrapperdescr_repr(PyObject * descr)72 wrapperdescr_repr(PyObject *descr)
73 {
74     return descr_repr((PyDescrObject *)descr,
75                       "<slot wrapper '%V' of '%s' objects>");
76 }
77 
78 static int
descr_check(PyDescrObject * descr,PyObject * obj)79 descr_check(PyDescrObject *descr, PyObject *obj)
80 {
81     if (!PyObject_TypeCheck(obj, descr->d_type)) {
82         PyErr_Format(PyExc_TypeError,
83                      "descriptor '%V' for '%.100s' objects "
84                      "doesn't apply to a '%.100s' object",
85                      descr_name((PyDescrObject *)descr), "?",
86                      descr->d_type->tp_name,
87                      Py_TYPE(obj)->tp_name);
88         return -1;
89     }
90     return 0;
91 }
92 
93 static PyObject *
classmethod_get(PyObject * self,PyObject * obj,PyObject * type)94 classmethod_get(PyObject *self, PyObject *obj, PyObject *type)
95 {
96     PyMethodDescrObject *descr = (PyMethodDescrObject *)self;
97     /* Ensure a valid type.  Class methods ignore obj. */
98     if (type == NULL) {
99         if (obj != NULL)
100             type = (PyObject *)Py_TYPE(obj);
101         else {
102             /* Wot - no type?! */
103             PyErr_Format(PyExc_TypeError,
104                          "descriptor '%V' for type '%.100s' "
105                          "needs either an object or a type",
106                          descr_name((PyDescrObject *)descr), "?",
107                          PyDescr_TYPE(descr)->tp_name);
108             return NULL;
109         }
110     }
111     if (!PyType_Check(type)) {
112         PyErr_Format(PyExc_TypeError,
113                      "descriptor '%V' for type '%.100s' "
114                      "needs a type, not a '%.100s' as arg 2",
115                      descr_name((PyDescrObject *)descr), "?",
116                      PyDescr_TYPE(descr)->tp_name,
117                      Py_TYPE(type)->tp_name);
118         return NULL;
119     }
120     if (!PyType_IsSubtype((PyTypeObject *)type, PyDescr_TYPE(descr))) {
121         PyErr_Format(PyExc_TypeError,
122                      "descriptor '%V' requires a subtype of '%.100s' "
123                      "but received '%.100s'",
124                      descr_name((PyDescrObject *)descr), "?",
125                      PyDescr_TYPE(descr)->tp_name,
126                      ((PyTypeObject *)type)->tp_name);
127         return NULL;
128     }
129     PyTypeObject *cls = NULL;
130     if (descr->d_method->ml_flags & METH_METHOD) {
131         cls = descr->d_common.d_type;
132     }
133     return PyCMethod_New(descr->d_method, type, NULL, cls);
134 }
135 
136 static PyObject *
method_get(PyObject * self,PyObject * obj,PyObject * type)137 method_get(PyObject *self, PyObject *obj, PyObject *type)
138 {
139     PyMethodDescrObject *descr = (PyMethodDescrObject *)self;
140     if (obj == NULL) {
141         return Py_NewRef(descr);
142     }
143     if (descr_check((PyDescrObject *)descr, obj) < 0) {
144         return NULL;
145     }
146     if (descr->d_method->ml_flags & METH_METHOD) {
147         if (PyType_Check(type)) {
148             return PyCMethod_New(descr->d_method, obj, NULL, descr->d_common.d_type);
149         } else {
150             PyErr_Format(PyExc_TypeError,
151                         "descriptor '%V' needs a type, not '%s', as arg 2",
152                         descr_name((PyDescrObject *)descr),
153                         Py_TYPE(type)->tp_name);
154             return NULL;
155         }
156     } else {
157         return PyCFunction_NewEx(descr->d_method, obj, NULL);
158     }
159 }
160 
161 static PyObject *
member_get(PyObject * self,PyObject * obj,PyObject * type)162 member_get(PyObject *self, PyObject *obj, PyObject *type)
163 {
164     PyMemberDescrObject *descr = (PyMemberDescrObject *)self;
165     if (obj == NULL) {
166         return Py_NewRef(descr);
167     }
168     if (descr_check((PyDescrObject *)descr, obj) < 0) {
169         return NULL;
170     }
171 
172     if (descr->d_member->flags & Py_AUDIT_READ) {
173         if (PySys_Audit("object.__getattr__", "Os",
174             obj ? obj : Py_None, descr->d_member->name) < 0) {
175             return NULL;
176         }
177     }
178 
179     return PyMember_GetOne((char *)obj, descr->d_member);
180 }
181 
182 static PyObject *
getset_get(PyObject * self,PyObject * obj,PyObject * type)183 getset_get(PyObject *self, PyObject *obj, PyObject *type)
184 {
185     PyGetSetDescrObject *descr = (PyGetSetDescrObject *)self;
186     if (obj == NULL) {
187         return Py_NewRef(descr);
188     }
189     if (descr_check((PyDescrObject *)descr, obj) < 0) {
190         return NULL;
191     }
192     if (descr->d_getset->get != NULL)
193         return descr_get_trampoline_call(
194             descr->d_getset->get, obj, descr->d_getset->closure);
195     PyErr_Format(PyExc_AttributeError,
196                  "attribute '%V' of '%.100s' objects is not readable",
197                  descr_name((PyDescrObject *)descr), "?",
198                  PyDescr_TYPE(descr)->tp_name);
199     return NULL;
200 }
201 
202 static PyObject *
wrapperdescr_get(PyObject * self,PyObject * obj,PyObject * type)203 wrapperdescr_get(PyObject *self, PyObject *obj, PyObject *type)
204 {
205     PyWrapperDescrObject *descr = (PyWrapperDescrObject *)self;
206     if (obj == NULL) {
207         return Py_NewRef(descr);
208     }
209     if (descr_check((PyDescrObject *)descr, obj) < 0) {
210         return NULL;
211     }
212     return PyWrapper_New((PyObject *)descr, obj);
213 }
214 
215 static int
descr_setcheck(PyDescrObject * descr,PyObject * obj,PyObject * value)216 descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value)
217 {
218     assert(obj != NULL);
219     if (!PyObject_TypeCheck(obj, descr->d_type)) {
220         PyErr_Format(PyExc_TypeError,
221                      "descriptor '%V' for '%.100s' objects "
222                      "doesn't apply to a '%.100s' object",
223                      descr_name(descr), "?",
224                      descr->d_type->tp_name,
225                      Py_TYPE(obj)->tp_name);
226         return -1;
227     }
228     return 0;
229 }
230 
231 static int
member_set(PyObject * self,PyObject * obj,PyObject * value)232 member_set(PyObject *self, PyObject *obj, PyObject *value)
233 {
234     PyMemberDescrObject *descr = (PyMemberDescrObject *)self;
235     if (descr_setcheck((PyDescrObject *)descr, obj, value) < 0) {
236         return -1;
237     }
238     return PyMember_SetOne((char *)obj, descr->d_member, value);
239 }
240 
241 static int
getset_set(PyObject * self,PyObject * obj,PyObject * value)242 getset_set(PyObject *self, PyObject *obj, PyObject *value)
243 {
244     PyGetSetDescrObject *descr = (PyGetSetDescrObject *)self;
245     if (descr_setcheck((PyDescrObject *)descr, obj, value) < 0) {
246         return -1;
247     }
248     if (descr->d_getset->set != NULL) {
249         return descr_set_trampoline_call(
250             descr->d_getset->set, obj, value,
251             descr->d_getset->closure);
252     }
253     PyErr_Format(PyExc_AttributeError,
254                  "attribute '%V' of '%.100s' objects is not writable",
255                  descr_name((PyDescrObject *)descr), "?",
256                  PyDescr_TYPE(descr)->tp_name);
257     return -1;
258 }
259 
260 
261 /* Vectorcall functions for each of the PyMethodDescr calling conventions.
262  *
263  * First, common helpers
264  */
265 static inline int
method_check_args(PyObject * func,PyObject * const * args,Py_ssize_t nargs,PyObject * kwnames)266 method_check_args(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
267 {
268     assert(!PyErr_Occurred());
269     if (nargs < 1) {
270         PyObject *funcstr = _PyObject_FunctionStr(func);
271         if (funcstr != NULL) {
272             PyErr_Format(PyExc_TypeError,
273                          "unbound method %U needs an argument", funcstr);
274             Py_DECREF(funcstr);
275         }
276         return -1;
277     }
278     PyObject *self = args[0];
279     if (descr_check((PyDescrObject *)func, self) < 0) {
280         return -1;
281     }
282     if (kwnames && PyTuple_GET_SIZE(kwnames)) {
283         PyObject *funcstr = _PyObject_FunctionStr(func);
284         if (funcstr != NULL) {
285             PyErr_Format(PyExc_TypeError,
286                          "%U takes no keyword arguments", funcstr);
287             Py_DECREF(funcstr);
288         }
289         return -1;
290     }
291     return 0;
292 }
293 
294 typedef void (*funcptr)(void);
295 
296 static inline funcptr
method_enter_call(PyThreadState * tstate,PyObject * func)297 method_enter_call(PyThreadState *tstate, PyObject *func)
298 {
299     if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) {
300         return NULL;
301     }
302     return (funcptr)((PyMethodDescrObject *)func)->d_method->ml_meth;
303 }
304 
305 /* Now the actual vectorcall functions */
306 static PyObject *
method_vectorcall_VARARGS(PyObject * func,PyObject * const * args,size_t nargsf,PyObject * kwnames)307 method_vectorcall_VARARGS(
308     PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
309 {
310     PyThreadState *tstate = _PyThreadState_GET();
311     Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
312     if (method_check_args(func, args, nargs, kwnames)) {
313         return NULL;
314     }
315     PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1);
316     if (argstuple == NULL) {
317         return NULL;
318     }
319     PyCFunction meth = (PyCFunction)method_enter_call(tstate, func);
320     if (meth == NULL) {
321         Py_DECREF(argstuple);
322         return NULL;
323     }
324     PyObject *result = _PyCFunction_TrampolineCall(
325         meth, args[0], argstuple);
326     Py_DECREF(argstuple);
327     _Py_LeaveRecursiveCallTstate(tstate);
328     return result;
329 }
330 
331 static PyObject *
method_vectorcall_VARARGS_KEYWORDS(PyObject * func,PyObject * const * args,size_t nargsf,PyObject * kwnames)332 method_vectorcall_VARARGS_KEYWORDS(
333     PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
334 {
335     PyThreadState *tstate = _PyThreadState_GET();
336     Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
337     if (method_check_args(func, args, nargs, NULL)) {
338         return NULL;
339     }
340     PyObject *argstuple = _PyTuple_FromArray(args+1, nargs-1);
341     if (argstuple == NULL) {
342         return NULL;
343     }
344     PyObject *result = NULL;
345     /* Create a temporary dict for keyword arguments */
346     PyObject *kwdict = NULL;
347     if (kwnames != NULL && PyTuple_GET_SIZE(kwnames) > 0) {
348         kwdict = _PyStack_AsDict(args + nargs, kwnames);
349         if (kwdict == NULL) {
350             goto exit;
351         }
352     }
353     PyCFunctionWithKeywords meth = (PyCFunctionWithKeywords)
354                                    method_enter_call(tstate, func);
355     if (meth == NULL) {
356         goto exit;
357     }
358     result = _PyCFunctionWithKeywords_TrampolineCall(
359         meth, args[0], argstuple, kwdict);
360     _Py_LeaveRecursiveCallTstate(tstate);
361 exit:
362     Py_DECREF(argstuple);
363     Py_XDECREF(kwdict);
364     return result;
365 }
366 
367 static PyObject *
method_vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject * func,PyObject * const * args,size_t nargsf,PyObject * kwnames)368 method_vectorcall_FASTCALL_KEYWORDS_METHOD(
369     PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
370 {
371     PyThreadState *tstate = _PyThreadState_GET();
372     Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
373     if (method_check_args(func, args, nargs, NULL)) {
374         return NULL;
375     }
376     PyCMethod meth = (PyCMethod) method_enter_call(tstate, func);
377     if (meth == NULL) {
378         return NULL;
379     }
380     PyObject *result = meth(args[0],
381                             ((PyMethodDescrObject *)func)->d_common.d_type,
382                             args+1, nargs-1, kwnames);
383     _Py_LeaveRecursiveCall();
384     return result;
385 }
386 
387 static PyObject *
method_vectorcall_FASTCALL(PyObject * func,PyObject * const * args,size_t nargsf,PyObject * kwnames)388 method_vectorcall_FASTCALL(
389     PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
390 {
391     PyThreadState *tstate = _PyThreadState_GET();
392     Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
393     if (method_check_args(func, args, nargs, kwnames)) {
394         return NULL;
395     }
396     PyCFunctionFast meth = (PyCFunctionFast)
397                             method_enter_call(tstate, func);
398     if (meth == NULL) {
399         return NULL;
400     }
401     PyObject *result = meth(args[0], args+1, nargs-1);
402     _Py_LeaveRecursiveCallTstate(tstate);
403     return result;
404 }
405 
406 static PyObject *
method_vectorcall_FASTCALL_KEYWORDS(PyObject * func,PyObject * const * args,size_t nargsf,PyObject * kwnames)407 method_vectorcall_FASTCALL_KEYWORDS(
408     PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
409 {
410     PyThreadState *tstate = _PyThreadState_GET();
411     Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
412     if (method_check_args(func, args, nargs, NULL)) {
413         return NULL;
414     }
415     PyCFunctionFastWithKeywords meth = (PyCFunctionFastWithKeywords)
416                                         method_enter_call(tstate, func);
417     if (meth == NULL) {
418         return NULL;
419     }
420     PyObject *result = meth(args[0], args+1, nargs-1, kwnames);
421     _Py_LeaveRecursiveCallTstate(tstate);
422     return result;
423 }
424 
425 static PyObject *
method_vectorcall_NOARGS(PyObject * func,PyObject * const * args,size_t nargsf,PyObject * kwnames)426 method_vectorcall_NOARGS(
427     PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
428 {
429     PyThreadState *tstate = _PyThreadState_GET();
430     Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
431     if (method_check_args(func, args, nargs, kwnames)) {
432         return NULL;
433     }
434     if (nargs != 1) {
435         PyObject *funcstr = _PyObject_FunctionStr(func);
436         if (funcstr != NULL) {
437             PyErr_Format(PyExc_TypeError,
438                 "%U takes no arguments (%zd given)", funcstr, nargs-1);
439             Py_DECREF(funcstr);
440         }
441         return NULL;
442     }
443     PyCFunction meth = (PyCFunction)method_enter_call(tstate, func);
444     if (meth == NULL) {
445         return NULL;
446     }
447     PyObject *result = _PyCFunction_TrampolineCall(meth, args[0], NULL);
448     _Py_LeaveRecursiveCallTstate(tstate);
449     return result;
450 }
451 
452 static PyObject *
method_vectorcall_O(PyObject * func,PyObject * const * args,size_t nargsf,PyObject * kwnames)453 method_vectorcall_O(
454     PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
455 {
456     PyThreadState *tstate = _PyThreadState_GET();
457     Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
458     if (method_check_args(func, args, nargs, kwnames)) {
459         return NULL;
460     }
461     if (nargs != 2) {
462         PyObject *funcstr = _PyObject_FunctionStr(func);
463         if (funcstr != NULL) {
464             PyErr_Format(PyExc_TypeError,
465                 "%U takes exactly one argument (%zd given)",
466                 funcstr, nargs-1);
467             Py_DECREF(funcstr);
468         }
469         return NULL;
470     }
471     PyCFunction meth = (PyCFunction)method_enter_call(tstate, func);
472     if (meth == NULL) {
473         return NULL;
474     }
475     PyObject *result = _PyCFunction_TrampolineCall(meth, args[0], args[1]);
476     _Py_LeaveRecursiveCallTstate(tstate);
477     return result;
478 }
479 
480 
481 /* Instances of classmethod_descriptor are unlikely to be called directly.
482    For one, the analogous class "classmethod" (for Python classes) is not
483    callable. Second, users are not likely to access a classmethod_descriptor
484    directly, since it means pulling it from the class __dict__.
485 
486    This is just an excuse to say that this doesn't need to be optimized:
487    we implement this simply by calling __get__ and then calling the result.
488 */
489 static PyObject *
classmethoddescr_call(PyObject * _descr,PyObject * args,PyObject * kwds)490 classmethoddescr_call(PyObject *_descr, PyObject *args,
491                       PyObject *kwds)
492 {
493     PyMethodDescrObject *descr = (PyMethodDescrObject *)_descr;
494     Py_ssize_t argc = PyTuple_GET_SIZE(args);
495     if (argc < 1) {
496         PyErr_Format(PyExc_TypeError,
497                      "descriptor '%V' of '%.100s' "
498                      "object needs an argument",
499                      descr_name((PyDescrObject *)descr), "?",
500                      PyDescr_TYPE(descr)->tp_name);
501         return NULL;
502     }
503     PyObject *self = PyTuple_GET_ITEM(args, 0);
504     PyObject *bound = classmethod_get((PyObject *)descr, NULL, self);
505     if (bound == NULL) {
506         return NULL;
507     }
508     PyObject *res = PyObject_VectorcallDict(bound, _PyTuple_ITEMS(args)+1,
509                                            argc-1, kwds);
510     Py_DECREF(bound);
511     return res;
512 }
513 
514 Py_LOCAL_INLINE(PyObject *)
wrapperdescr_raw_call(PyWrapperDescrObject * descr,PyObject * self,PyObject * args,PyObject * kwds)515 wrapperdescr_raw_call(PyWrapperDescrObject *descr, PyObject *self,
516                       PyObject *args, PyObject *kwds)
517 {
518     wrapperfunc wrapper = descr->d_base->wrapper;
519 
520     if (descr->d_base->flags & PyWrapperFlag_KEYWORDS) {
521         wrapperfunc_kwds wk = (wrapperfunc_kwds)(void(*)(void))wrapper;
522         return (*wk)(self, args, descr->d_wrapped, kwds);
523     }
524 
525     if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_GET_SIZE(kwds) != 0)) {
526         PyErr_Format(PyExc_TypeError,
527                      "wrapper %s() takes no keyword arguments",
528                      descr->d_base->name);
529         return NULL;
530     }
531     return (*wrapper)(self, args, descr->d_wrapped);
532 }
533 
534 static PyObject *
wrapperdescr_call(PyObject * _descr,PyObject * args,PyObject * kwds)535 wrapperdescr_call(PyObject *_descr, PyObject *args, PyObject *kwds)
536 {
537     PyWrapperDescrObject *descr = (PyWrapperDescrObject *)_descr;
538     Py_ssize_t argc;
539     PyObject *self, *result;
540 
541     /* Make sure that the first argument is acceptable as 'self' */
542     assert(PyTuple_Check(args));
543     argc = PyTuple_GET_SIZE(args);
544     if (argc < 1) {
545         PyErr_Format(PyExc_TypeError,
546                      "descriptor '%V' of '%.100s' "
547                      "object needs an argument",
548                      descr_name((PyDescrObject *)descr), "?",
549                      PyDescr_TYPE(descr)->tp_name);
550         return NULL;
551     }
552     self = PyTuple_GET_ITEM(args, 0);
553     if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
554                                   (PyObject *)PyDescr_TYPE(descr))) {
555         PyErr_Format(PyExc_TypeError,
556                      "descriptor '%V' "
557                      "requires a '%.100s' object "
558                      "but received a '%.100s'",
559                      descr_name((PyDescrObject *)descr), "?",
560                      PyDescr_TYPE(descr)->tp_name,
561                      Py_TYPE(self)->tp_name);
562         return NULL;
563     }
564 
565     args = PyTuple_GetSlice(args, 1, argc);
566     if (args == NULL) {
567         return NULL;
568     }
569     result = wrapperdescr_raw_call(descr, self, args, kwds);
570     Py_DECREF(args);
571     return result;
572 }
573 
574 
575 static PyObject *
method_get_doc(PyObject * _descr,void * closure)576 method_get_doc(PyObject *_descr, void *closure)
577 {
578     PyMethodDescrObject *descr = (PyMethodDescrObject *)_descr;
579     return _PyType_GetDocFromInternalDoc(descr->d_method->ml_name, descr->d_method->ml_doc);
580 }
581 
582 static PyObject *
method_get_text_signature(PyObject * _descr,void * closure)583 method_get_text_signature(PyObject *_descr, void *closure)
584 {
585     PyMethodDescrObject *descr = (PyMethodDescrObject *)_descr;
586     return _PyType_GetTextSignatureFromInternalDoc(descr->d_method->ml_name,
587                                                    descr->d_method->ml_doc,
588                                                    descr->d_method->ml_flags);
589 }
590 
591 static PyObject *
calculate_qualname(PyDescrObject * descr)592 calculate_qualname(PyDescrObject *descr)
593 {
594     PyObject *type_qualname, *res;
595 
596     if (descr->d_name == NULL || !PyUnicode_Check(descr->d_name)) {
597         PyErr_SetString(PyExc_TypeError,
598                         "<descriptor>.__name__ is not a unicode object");
599         return NULL;
600     }
601 
602     type_qualname = PyObject_GetAttr(
603             (PyObject *)descr->d_type, &_Py_ID(__qualname__));
604     if (type_qualname == NULL)
605         return NULL;
606 
607     if (!PyUnicode_Check(type_qualname)) {
608         PyErr_SetString(PyExc_TypeError, "<descriptor>.__objclass__."
609                         "__qualname__ is not a unicode object");
610         Py_XDECREF(type_qualname);
611         return NULL;
612     }
613 
614     res = PyUnicode_FromFormat("%S.%S", type_qualname, descr->d_name);
615     Py_DECREF(type_qualname);
616     return res;
617 }
618 
619 static PyObject *
descr_get_qualname(PyObject * self,void * Py_UNUSED (ignored))620 descr_get_qualname(PyObject *self, void *Py_UNUSED(ignored))
621 {
622     PyDescrObject *descr = (PyDescrObject *)self;
623     if (descr->d_qualname == NULL)
624         descr->d_qualname = calculate_qualname(descr);
625     return Py_XNewRef(descr->d_qualname);
626 }
627 
628 static PyObject *
descr_reduce(PyObject * self,PyObject * Py_UNUSED (ignored))629 descr_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
630 {
631     PyDescrObject *descr = (PyDescrObject *)self;
632     return Py_BuildValue("N(OO)", _PyEval_GetBuiltin(&_Py_ID(getattr)),
633                          PyDescr_TYPE(descr), PyDescr_NAME(descr));
634 }
635 
636 static PyMethodDef descr_methods[] = {
637     {"__reduce__", descr_reduce, METH_NOARGS, NULL},
638     {NULL, NULL}
639 };
640 
641 static PyMemberDef descr_members[] = {
642     {"__objclass__", _Py_T_OBJECT, offsetof(PyDescrObject, d_type), Py_READONLY},
643     {"__name__", _Py_T_OBJECT, offsetof(PyDescrObject, d_name), Py_READONLY},
644     {0}
645 };
646 
647 static PyGetSetDef method_getset[] = {
648     {"__doc__", method_get_doc},
649     {"__qualname__", descr_get_qualname},
650     {"__text_signature__", method_get_text_signature},
651     {0}
652 };
653 
654 static PyObject *
member_get_doc(PyObject * _descr,void * closure)655 member_get_doc(PyObject *_descr, void *closure)
656 {
657     PyMemberDescrObject *descr = (PyMemberDescrObject *)_descr;
658     if (descr->d_member->doc == NULL) {
659         Py_RETURN_NONE;
660     }
661     return PyUnicode_FromString(descr->d_member->doc);
662 }
663 
664 static PyGetSetDef member_getset[] = {
665     {"__doc__", member_get_doc},
666     {"__qualname__", descr_get_qualname},
667     {0}
668 };
669 
670 static PyObject *
getset_get_doc(PyObject * self,void * closure)671 getset_get_doc(PyObject *self, void *closure)
672 {
673     PyGetSetDescrObject *descr = (PyGetSetDescrObject *)self;
674     if (descr->d_getset->doc == NULL) {
675         Py_RETURN_NONE;
676     }
677     return PyUnicode_FromString(descr->d_getset->doc);
678 }
679 
680 static PyGetSetDef getset_getset[] = {
681     {"__doc__", getset_get_doc},
682     {"__qualname__", descr_get_qualname},
683     {0}
684 };
685 
686 static PyObject *
wrapperdescr_get_doc(PyObject * self,void * closure)687 wrapperdescr_get_doc(PyObject *self, void *closure)
688 {
689     PyWrapperDescrObject *descr = (PyWrapperDescrObject *)self;
690     return _PyType_GetDocFromInternalDoc(descr->d_base->name, descr->d_base->doc);
691 }
692 
693 static PyObject *
wrapperdescr_get_text_signature(PyObject * self,void * closure)694 wrapperdescr_get_text_signature(PyObject *self, void *closure)
695 {
696     PyWrapperDescrObject *descr = (PyWrapperDescrObject *)self;
697     return _PyType_GetTextSignatureFromInternalDoc(descr->d_base->name,
698                                                    descr->d_base->doc, 0);
699 }
700 
701 static PyGetSetDef wrapperdescr_getset[] = {
702     {"__doc__", wrapperdescr_get_doc},
703     {"__qualname__", descr_get_qualname},
704     {"__text_signature__", wrapperdescr_get_text_signature},
705     {0}
706 };
707 
708 static int
descr_traverse(PyObject * self,visitproc visit,void * arg)709 descr_traverse(PyObject *self, visitproc visit, void *arg)
710 {
711     PyDescrObject *descr = (PyDescrObject *)self;
712     Py_VISIT(descr->d_type);
713     return 0;
714 }
715 
716 PyTypeObject PyMethodDescr_Type = {
717     PyVarObject_HEAD_INIT(&PyType_Type, 0)
718     "method_descriptor",
719     sizeof(PyMethodDescrObject),
720     0,
721     descr_dealloc,                              /* tp_dealloc */
722     offsetof(PyMethodDescrObject, vectorcall),  /* tp_vectorcall_offset */
723     0,                                          /* tp_getattr */
724     0,                                          /* tp_setattr */
725     0,                                          /* tp_as_async */
726     method_repr,                                /* tp_repr */
727     0,                                          /* tp_as_number */
728     0,                                          /* tp_as_sequence */
729     0,                                          /* tp_as_mapping */
730     0,                                          /* tp_hash */
731     PyVectorcall_Call,                          /* tp_call */
732     0,                                          /* tp_str */
733     PyObject_GenericGetAttr,                    /* tp_getattro */
734     0,                                          /* tp_setattro */
735     0,                                          /* tp_as_buffer */
736     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
737     Py_TPFLAGS_HAVE_VECTORCALL |
738     Py_TPFLAGS_METHOD_DESCRIPTOR,               /* tp_flags */
739     0,                                          /* tp_doc */
740     descr_traverse,                             /* tp_traverse */
741     0,                                          /* tp_clear */
742     0,                                          /* tp_richcompare */
743     0,                                          /* tp_weaklistoffset */
744     0,                                          /* tp_iter */
745     0,                                          /* tp_iternext */
746     descr_methods,                              /* tp_methods */
747     descr_members,                              /* tp_members */
748     method_getset,                              /* tp_getset */
749     0,                                          /* tp_base */
750     0,                                          /* tp_dict */
751     method_get,                                 /* tp_descr_get */
752     0,                                          /* tp_descr_set */
753 };
754 
755 /* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */
756 PyTypeObject PyClassMethodDescr_Type = {
757     PyVarObject_HEAD_INIT(&PyType_Type, 0)
758     "classmethod_descriptor",
759     sizeof(PyMethodDescrObject),
760     0,
761     descr_dealloc,                              /* tp_dealloc */
762     0,                                          /* tp_vectorcall_offset */
763     0,                                          /* tp_getattr */
764     0,                                          /* tp_setattr */
765     0,                                          /* tp_as_async */
766     method_repr,                                /* tp_repr */
767     0,                                          /* tp_as_number */
768     0,                                          /* tp_as_sequence */
769     0,                                          /* tp_as_mapping */
770     0,                                          /* tp_hash */
771     classmethoddescr_call,                      /* tp_call */
772     0,                                          /* tp_str */
773     PyObject_GenericGetAttr,                    /* tp_getattro */
774     0,                                          /* tp_setattro */
775     0,                                          /* tp_as_buffer */
776     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
777     0,                                          /* tp_doc */
778     descr_traverse,                             /* tp_traverse */
779     0,                                          /* tp_clear */
780     0,                                          /* tp_richcompare */
781     0,                                          /* tp_weaklistoffset */
782     0,                                          /* tp_iter */
783     0,                                          /* tp_iternext */
784     0,                                          /* tp_methods */
785     descr_members,                              /* tp_members */
786     method_getset,                              /* tp_getset */
787     0,                                          /* tp_base */
788     0,                                          /* tp_dict */
789     classmethod_get,                            /* tp_descr_get */
790     0,                                          /* tp_descr_set */
791 };
792 
793 PyTypeObject PyMemberDescr_Type = {
794     PyVarObject_HEAD_INIT(&PyType_Type, 0)
795     "member_descriptor",
796     sizeof(PyMemberDescrObject),
797     0,
798     descr_dealloc,                              /* tp_dealloc */
799     0,                                          /* tp_vectorcall_offset */
800     0,                                          /* tp_getattr */
801     0,                                          /* tp_setattr */
802     0,                                          /* tp_as_async */
803     member_repr,                                /* tp_repr */
804     0,                                          /* tp_as_number */
805     0,                                          /* tp_as_sequence */
806     0,                                          /* tp_as_mapping */
807     0,                                          /* tp_hash */
808     0,                                          /* tp_call */
809     0,                                          /* tp_str */
810     PyObject_GenericGetAttr,                    /* tp_getattro */
811     0,                                          /* tp_setattro */
812     0,                                          /* tp_as_buffer */
813     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
814     0,                                          /* tp_doc */
815     descr_traverse,                             /* tp_traverse */
816     0,                                          /* tp_clear */
817     0,                                          /* tp_richcompare */
818     0,                                          /* tp_weaklistoffset */
819     0,                                          /* tp_iter */
820     0,                                          /* tp_iternext */
821     descr_methods,                              /* tp_methods */
822     descr_members,                              /* tp_members */
823     member_getset,                              /* tp_getset */
824     0,                                          /* tp_base */
825     0,                                          /* tp_dict */
826     member_get,                                 /* tp_descr_get */
827     member_set,                                 /* tp_descr_set */
828 };
829 
830 PyTypeObject PyGetSetDescr_Type = {
831     PyVarObject_HEAD_INIT(&PyType_Type, 0)
832     "getset_descriptor",
833     sizeof(PyGetSetDescrObject),
834     0,
835     descr_dealloc,                              /* tp_dealloc */
836     0,                                          /* tp_vectorcall_offset */
837     0,                                          /* tp_getattr */
838     0,                                          /* tp_setattr */
839     0,                                          /* tp_as_async */
840     getset_repr,                                /* tp_repr */
841     0,                                          /* tp_as_number */
842     0,                                          /* tp_as_sequence */
843     0,                                          /* tp_as_mapping */
844     0,                                          /* tp_hash */
845     0,                                          /* tp_call */
846     0,                                          /* tp_str */
847     PyObject_GenericGetAttr,                    /* tp_getattro */
848     0,                                          /* tp_setattro */
849     0,                                          /* tp_as_buffer */
850     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
851     0,                                          /* tp_doc */
852     descr_traverse,                             /* tp_traverse */
853     0,                                          /* tp_clear */
854     0,                                          /* tp_richcompare */
855     0,                                          /* tp_weaklistoffset */
856     0,                                          /* tp_iter */
857     0,                                          /* tp_iternext */
858     0,                                          /* tp_methods */
859     descr_members,                              /* tp_members */
860     getset_getset,                              /* tp_getset */
861     0,                                          /* tp_base */
862     0,                                          /* tp_dict */
863     getset_get,                                 /* tp_descr_get */
864     getset_set,                                 /* tp_descr_set */
865 };
866 
867 PyTypeObject PyWrapperDescr_Type = {
868     PyVarObject_HEAD_INIT(&PyType_Type, 0)
869     "wrapper_descriptor",
870     sizeof(PyWrapperDescrObject),
871     0,
872     descr_dealloc,                              /* tp_dealloc */
873     0,                                          /* tp_vectorcall_offset */
874     0,                                          /* tp_getattr */
875     0,                                          /* tp_setattr */
876     0,                                          /* tp_as_async */
877     wrapperdescr_repr,                          /* tp_repr */
878     0,                                          /* tp_as_number */
879     0,                                          /* tp_as_sequence */
880     0,                                          /* tp_as_mapping */
881     0,                                          /* tp_hash */
882     wrapperdescr_call,                          /* tp_call */
883     0,                                          /* tp_str */
884     PyObject_GenericGetAttr,                    /* tp_getattro */
885     0,                                          /* tp_setattro */
886     0,                                          /* tp_as_buffer */
887     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
888     Py_TPFLAGS_METHOD_DESCRIPTOR,               /* tp_flags */
889     0,                                          /* tp_doc */
890     descr_traverse,                             /* tp_traverse */
891     0,                                          /* tp_clear */
892     0,                                          /* tp_richcompare */
893     0,                                          /* tp_weaklistoffset */
894     0,                                          /* tp_iter */
895     0,                                          /* tp_iternext */
896     descr_methods,                              /* tp_methods */
897     descr_members,                              /* tp_members */
898     wrapperdescr_getset,                        /* tp_getset */
899     0,                                          /* tp_base */
900     0,                                          /* tp_dict */
901     wrapperdescr_get,                           /* tp_descr_get */
902     0,                                          /* tp_descr_set */
903 };
904 
905 static PyDescrObject *
descr_new(PyTypeObject * descrtype,PyTypeObject * type,const char * name)906 descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)
907 {
908     PyDescrObject *descr;
909 
910     descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);
911     if (descr != NULL) {
912         _PyObject_SetDeferredRefcount((PyObject *)descr);
913         descr->d_type = (PyTypeObject*)Py_XNewRef(type);
914         descr->d_name = PyUnicode_InternFromString(name);
915         if (descr->d_name == NULL) {
916             Py_SETREF(descr, NULL);
917         }
918         else {
919             descr->d_qualname = NULL;
920         }
921     }
922     return descr;
923 }
924 
925 PyObject *
PyDescr_NewMethod(PyTypeObject * type,PyMethodDef * method)926 PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)
927 {
928     /* Figure out correct vectorcall function to use */
929     vectorcallfunc vectorcall;
930     switch (method->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS |
931                                 METH_O | METH_KEYWORDS | METH_METHOD))
932     {
933         case METH_VARARGS:
934             vectorcall = method_vectorcall_VARARGS;
935             break;
936         case METH_VARARGS | METH_KEYWORDS:
937             vectorcall = method_vectorcall_VARARGS_KEYWORDS;
938             break;
939         case METH_FASTCALL:
940             vectorcall = method_vectorcall_FASTCALL;
941             break;
942         case METH_FASTCALL | METH_KEYWORDS:
943             vectorcall = method_vectorcall_FASTCALL_KEYWORDS;
944             break;
945         case METH_NOARGS:
946             vectorcall = method_vectorcall_NOARGS;
947             break;
948         case METH_O:
949             vectorcall = method_vectorcall_O;
950             break;
951         case METH_METHOD | METH_FASTCALL | METH_KEYWORDS:
952             vectorcall = method_vectorcall_FASTCALL_KEYWORDS_METHOD;
953             break;
954         default:
955             PyErr_Format(PyExc_SystemError,
956                          "%s() method: bad call flags", method->ml_name);
957             return NULL;
958     }
959 
960     PyMethodDescrObject *descr;
961 
962     descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type,
963                                              type, method->ml_name);
964     if (descr != NULL) {
965         descr->d_method = method;
966         descr->vectorcall = vectorcall;
967     }
968     return (PyObject *)descr;
969 }
970 
971 PyObject *
PyDescr_NewClassMethod(PyTypeObject * type,PyMethodDef * method)972 PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)
973 {
974     PyMethodDescrObject *descr;
975 
976     descr = (PyMethodDescrObject *)descr_new(&PyClassMethodDescr_Type,
977                                              type, method->ml_name);
978     if (descr != NULL)
979         descr->d_method = method;
980     return (PyObject *)descr;
981 }
982 
983 PyObject *
PyDescr_NewMember(PyTypeObject * type,PyMemberDef * member)984 PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member)
985 {
986     PyMemberDescrObject *descr;
987 
988     if (member->flags & Py_RELATIVE_OFFSET) {
989         PyErr_SetString(
990             PyExc_SystemError,
991             "PyDescr_NewMember used with Py_RELATIVE_OFFSET");
992         return NULL;
993     }
994     descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type,
995                                              type, member->name);
996     if (descr != NULL)
997         descr->d_member = member;
998     return (PyObject *)descr;
999 }
1000 
1001 PyObject *
PyDescr_NewGetSet(PyTypeObject * type,PyGetSetDef * getset)1002 PyDescr_NewGetSet(PyTypeObject *type, PyGetSetDef *getset)
1003 {
1004     PyGetSetDescrObject *descr;
1005 
1006     descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type,
1007                                              type, getset->name);
1008     if (descr != NULL)
1009         descr->d_getset = getset;
1010     return (PyObject *)descr;
1011 }
1012 
1013 PyObject *
PyDescr_NewWrapper(PyTypeObject * type,struct wrapperbase * base,void * wrapped)1014 PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)
1015 {
1016     PyWrapperDescrObject *descr;
1017 
1018     descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,
1019                                              type, base->name);
1020     if (descr != NULL) {
1021         descr->d_base = base;
1022         descr->d_wrapped = wrapped;
1023     }
1024     return (PyObject *)descr;
1025 }
1026 
1027 int
PyDescr_IsData(PyObject * ob)1028 PyDescr_IsData(PyObject *ob)
1029 {
1030     return Py_TYPE(ob)->tp_descr_set != NULL;
1031 }
1032 
1033 /* --- mappingproxy: read-only proxy for mappings --- */
1034 
1035 /* This has no reason to be in this file except that adding new files is a
1036    bit of a pain */
1037 
1038 typedef struct {
1039     PyObject_HEAD
1040     PyObject *mapping;
1041 } mappingproxyobject;
1042 
1043 static Py_ssize_t
mappingproxy_len(PyObject * self)1044 mappingproxy_len(PyObject *self)
1045 {
1046     mappingproxyobject *pp = (mappingproxyobject *)self;
1047     return PyObject_Size(pp->mapping);
1048 }
1049 
1050 static PyObject *
mappingproxy_getitem(PyObject * self,PyObject * key)1051 mappingproxy_getitem(PyObject *self, PyObject *key)
1052 {
1053     mappingproxyobject *pp = (mappingproxyobject *)self;
1054     return PyObject_GetItem(pp->mapping, key);
1055 }
1056 
1057 static PyMappingMethods mappingproxy_as_mapping = {
1058     mappingproxy_len,                           /* mp_length */
1059     mappingproxy_getitem,                       /* mp_subscript */
1060     0,                                          /* mp_ass_subscript */
1061 };
1062 
1063 static PyObject *
mappingproxy_or(PyObject * left,PyObject * right)1064 mappingproxy_or(PyObject *left, PyObject *right)
1065 {
1066     if (PyObject_TypeCheck(left, &PyDictProxy_Type)) {
1067         left = ((mappingproxyobject*)left)->mapping;
1068     }
1069     if (PyObject_TypeCheck(right, &PyDictProxy_Type)) {
1070         right = ((mappingproxyobject*)right)->mapping;
1071     }
1072     return PyNumber_Or(left, right);
1073 }
1074 
1075 static PyObject *
mappingproxy_ior(PyObject * self,PyObject * Py_UNUSED (other))1076 mappingproxy_ior(PyObject *self, PyObject *Py_UNUSED(other))
1077 {
1078     return PyErr_Format(PyExc_TypeError,
1079         "'|=' is not supported by %s; use '|' instead", Py_TYPE(self)->tp_name);
1080 }
1081 
1082 static PyNumberMethods mappingproxy_as_number = {
1083     .nb_or = mappingproxy_or,
1084     .nb_inplace_or = mappingproxy_ior,
1085 };
1086 
1087 static int
mappingproxy_contains(PyObject * self,PyObject * key)1088 mappingproxy_contains(PyObject *self, PyObject *key)
1089 {
1090     mappingproxyobject *pp = (mappingproxyobject *)self;
1091     if (PyDict_CheckExact(pp->mapping))
1092         return PyDict_Contains(pp->mapping, key);
1093     else
1094         return PySequence_Contains(pp->mapping, key);
1095 }
1096 
1097 static PySequenceMethods mappingproxy_as_sequence = {
1098     0,                                          /* sq_length */
1099     0,                                          /* sq_concat */
1100     0,                                          /* sq_repeat */
1101     0,                                          /* sq_item */
1102     0,                                          /* sq_slice */
1103     0,                                          /* sq_ass_item */
1104     0,                                          /* sq_ass_slice */
1105     mappingproxy_contains,                      /* sq_contains */
1106     0,                                          /* sq_inplace_concat */
1107     0,                                          /* sq_inplace_repeat */
1108 };
1109 
1110 static PyObject *
mappingproxy_get(PyObject * self,PyObject * const * args,Py_ssize_t nargs)1111 mappingproxy_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
1112 {
1113     mappingproxyobject *pp = (mappingproxyobject *)self;
1114     /* newargs: mapping, key, default=None */
1115     PyObject *newargs[3];
1116     newargs[0] = pp->mapping;
1117     newargs[2] = Py_None;
1118 
1119     if (!_PyArg_UnpackStack(args, nargs, "get", 1, 2,
1120                             &newargs[1], &newargs[2]))
1121     {
1122         return NULL;
1123     }
1124     return PyObject_VectorcallMethod(&_Py_ID(get), newargs,
1125                                      3 | PY_VECTORCALL_ARGUMENTS_OFFSET,
1126                                      NULL);
1127 }
1128 
1129 static PyObject *
mappingproxy_keys(PyObject * self,PyObject * Py_UNUSED (ignored))1130 mappingproxy_keys(PyObject *self, PyObject *Py_UNUSED(ignored))
1131 {
1132     mappingproxyobject *pp = (mappingproxyobject *)self;
1133     return PyObject_CallMethodNoArgs(pp->mapping, &_Py_ID(keys));
1134 }
1135 
1136 static PyObject *
mappingproxy_values(PyObject * self,PyObject * Py_UNUSED (ignored))1137 mappingproxy_values(PyObject *self, PyObject *Py_UNUSED(ignored))
1138 {
1139     mappingproxyobject *pp = (mappingproxyobject *)self;
1140     return PyObject_CallMethodNoArgs(pp->mapping, &_Py_ID(values));
1141 }
1142 
1143 static PyObject *
mappingproxy_items(PyObject * self,PyObject * Py_UNUSED (ignored))1144 mappingproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored))
1145 {
1146     mappingproxyobject *pp = (mappingproxyobject *)self;
1147     return PyObject_CallMethodNoArgs(pp->mapping, &_Py_ID(items));
1148 }
1149 
1150 static PyObject *
mappingproxy_copy(PyObject * self,PyObject * Py_UNUSED (ignored))1151 mappingproxy_copy(PyObject *self, PyObject *Py_UNUSED(ignored))
1152 {
1153     mappingproxyobject *pp = (mappingproxyobject *)self;
1154     return PyObject_CallMethodNoArgs(pp->mapping, &_Py_ID(copy));
1155 }
1156 
1157 static PyObject *
mappingproxy_reversed(PyObject * self,PyObject * Py_UNUSED (ignored))1158 mappingproxy_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
1159 {
1160     mappingproxyobject *pp = (mappingproxyobject *)self;
1161     return PyObject_CallMethodNoArgs(pp->mapping, &_Py_ID(__reversed__));
1162 }
1163 
1164 /* WARNING: mappingproxy methods must not give access
1165             to the underlying mapping */
1166 
1167 static PyMethodDef mappingproxy_methods[] = {
1168     {"get",       _PyCFunction_CAST(mappingproxy_get), METH_FASTCALL,
1169      PyDoc_STR("get($self, key, default=None, /)\n--\n\n"
1170         "Return the value for key if key is in the mapping, else default.")},
1171     {"keys",      mappingproxy_keys,       METH_NOARGS,
1172      PyDoc_STR("D.keys() -> a set-like object providing a view on D's keys")},
1173     {"values",    mappingproxy_values,     METH_NOARGS,
1174      PyDoc_STR("D.values() -> an object providing a view on D's values")},
1175     {"items",     mappingproxy_items,      METH_NOARGS,
1176      PyDoc_STR("D.items() -> a set-like object providing a view on D's items")},
1177     {"copy",      mappingproxy_copy,       METH_NOARGS,
1178      PyDoc_STR("D.copy() -> a shallow copy of D")},
1179     {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS,
1180      PyDoc_STR("See PEP 585")},
1181     {"__reversed__", mappingproxy_reversed, METH_NOARGS,
1182      PyDoc_STR("D.__reversed__() -> reverse iterator")},
1183     {0}
1184 };
1185 
1186 static void
mappingproxy_dealloc(PyObject * self)1187 mappingproxy_dealloc(PyObject *self)
1188 {
1189     mappingproxyobject *pp = (mappingproxyobject *)self;
1190     _PyObject_GC_UNTRACK(pp);
1191     Py_DECREF(pp->mapping);
1192     PyObject_GC_Del(pp);
1193 }
1194 
1195 static PyObject *
mappingproxy_getiter(PyObject * self)1196 mappingproxy_getiter(PyObject *self)
1197 {
1198     mappingproxyobject *pp = (mappingproxyobject *)self;
1199     return PyObject_GetIter(pp->mapping);
1200 }
1201 
1202 static Py_hash_t
mappingproxy_hash(PyObject * self)1203 mappingproxy_hash(PyObject *self)
1204 {
1205     mappingproxyobject *pp = (mappingproxyobject *)self;
1206     return PyObject_Hash(pp->mapping);
1207 }
1208 
1209 static PyObject *
mappingproxy_str(PyObject * self)1210 mappingproxy_str(PyObject *self)
1211 {
1212     mappingproxyobject *pp = (mappingproxyobject *)self;
1213     return PyObject_Str(pp->mapping);
1214 }
1215 
1216 static PyObject *
mappingproxy_repr(PyObject * self)1217 mappingproxy_repr(PyObject *self)
1218 {
1219     mappingproxyobject *pp = (mappingproxyobject *)self;
1220     return PyUnicode_FromFormat("mappingproxy(%R)", pp->mapping);
1221 }
1222 
1223 static int
mappingproxy_traverse(PyObject * self,visitproc visit,void * arg)1224 mappingproxy_traverse(PyObject *self, visitproc visit, void *arg)
1225 {
1226     mappingproxyobject *pp = (mappingproxyobject *)self;
1227     Py_VISIT(pp->mapping);
1228     return 0;
1229 }
1230 
1231 static PyObject *
mappingproxy_richcompare(PyObject * self,PyObject * w,int op)1232 mappingproxy_richcompare(PyObject *self, PyObject *w, int op)
1233 {
1234     mappingproxyobject *v = (mappingproxyobject *)self;
1235     return PyObject_RichCompare(v->mapping, w, op);
1236 }
1237 
1238 static int
mappingproxy_check_mapping(PyObject * mapping)1239 mappingproxy_check_mapping(PyObject *mapping)
1240 {
1241     if (!PyMapping_Check(mapping)
1242         || PyList_Check(mapping)
1243         || PyTuple_Check(mapping)) {
1244         PyErr_Format(PyExc_TypeError,
1245                     "mappingproxy() argument must be a mapping, not %s",
1246                     Py_TYPE(mapping)->tp_name);
1247         return -1;
1248     }
1249     return 0;
1250 }
1251 
1252 /*[clinic input]
1253 @classmethod
1254 mappingproxy.__new__ as mappingproxy_new
1255 
1256     mapping: object
1257 
1258 Read-only proxy of a mapping.
1259 [clinic start generated code]*/
1260 
1261 static PyObject *
mappingproxy_new_impl(PyTypeObject * type,PyObject * mapping)1262 mappingproxy_new_impl(PyTypeObject *type, PyObject *mapping)
1263 /*[clinic end generated code: output=65f27f02d5b68fa7 input=c156df096ef7590c]*/
1264 {
1265     mappingproxyobject *mappingproxy;
1266 
1267     if (mappingproxy_check_mapping(mapping) == -1)
1268         return NULL;
1269 
1270     mappingproxy = PyObject_GC_New(mappingproxyobject, &PyDictProxy_Type);
1271     if (mappingproxy == NULL)
1272         return NULL;
1273     mappingproxy->mapping = Py_NewRef(mapping);
1274     _PyObject_GC_TRACK(mappingproxy);
1275     return (PyObject *)mappingproxy;
1276 }
1277 
1278 PyObject *
PyDictProxy_New(PyObject * mapping)1279 PyDictProxy_New(PyObject *mapping)
1280 {
1281     mappingproxyobject *pp;
1282 
1283     if (mappingproxy_check_mapping(mapping) == -1)
1284         return NULL;
1285 
1286     pp = PyObject_GC_New(mappingproxyobject, &PyDictProxy_Type);
1287     if (pp != NULL) {
1288         pp->mapping = Py_NewRef(mapping);
1289         _PyObject_GC_TRACK(pp);
1290     }
1291     return (PyObject *)pp;
1292 }
1293 
1294 
1295 /* --- Wrapper object for "slot" methods --- */
1296 
1297 /* This has no reason to be in this file except that adding new files is a
1298    bit of a pain */
1299 
1300 typedef struct {
1301     PyObject_HEAD
1302     PyWrapperDescrObject *descr;
1303     PyObject *self;
1304 } wrapperobject;
1305 
1306 #define Wrapper_Check(v) Py_IS_TYPE(v, &_PyMethodWrapper_Type)
1307 
1308 static void
wrapper_dealloc(PyObject * self)1309 wrapper_dealloc(PyObject *self)
1310 {
1311     wrapperobject *wp = (wrapperobject *)self;
1312     PyObject_GC_UnTrack(wp);
1313     Py_TRASHCAN_BEGIN(wp, wrapper_dealloc)
1314     Py_XDECREF(wp->descr);
1315     Py_XDECREF(wp->self);
1316     PyObject_GC_Del(wp);
1317     Py_TRASHCAN_END
1318 }
1319 
1320 static PyObject *
wrapper_richcompare(PyObject * a,PyObject * b,int op)1321 wrapper_richcompare(PyObject *a, PyObject *b, int op)
1322 {
1323     wrapperobject *wa, *wb;
1324     int eq;
1325 
1326     assert(a != NULL && b != NULL);
1327 
1328     /* both arguments should be wrapperobjects */
1329     if ((op != Py_EQ && op != Py_NE)
1330         || !Wrapper_Check(a) || !Wrapper_Check(b))
1331     {
1332         Py_RETURN_NOTIMPLEMENTED;
1333     }
1334 
1335     wa = (wrapperobject *)a;
1336     wb = (wrapperobject *)b;
1337     eq = (wa->descr == wb->descr && wa->self == wb->self);
1338     if (eq == (op == Py_EQ)) {
1339         Py_RETURN_TRUE;
1340     }
1341     else {
1342         Py_RETURN_FALSE;
1343     }
1344 }
1345 
1346 static Py_hash_t
wrapper_hash(PyObject * self)1347 wrapper_hash(PyObject *self)
1348 {
1349     wrapperobject *wp = (wrapperobject *)self;
1350     Py_hash_t x, y;
1351     x = PyObject_GenericHash(wp->self);
1352     y = _Py_HashPointer(wp->descr);
1353     x = x ^ y;
1354     if (x == -1)
1355         x = -2;
1356     return x;
1357 }
1358 
1359 static PyObject *
wrapper_repr(PyObject * self)1360 wrapper_repr(PyObject *self)
1361 {
1362     wrapperobject *wp = (wrapperobject *)self;
1363     return PyUnicode_FromFormat("<method-wrapper '%s' of %s object at %p>",
1364                                wp->descr->d_base->name,
1365                                Py_TYPE(wp->self)->tp_name,
1366                                wp->self);
1367 }
1368 
1369 static PyObject *
wrapper_reduce(PyObject * self,PyObject * Py_UNUSED (ignored))1370 wrapper_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
1371 {
1372     wrapperobject *wp = (wrapperobject *)self;
1373     return Py_BuildValue("N(OO)", _PyEval_GetBuiltin(&_Py_ID(getattr)),
1374                          wp->self, PyDescr_NAME(wp->descr));
1375 }
1376 
1377 static PyMethodDef wrapper_methods[] = {
1378     {"__reduce__", wrapper_reduce, METH_NOARGS, NULL},
1379     {NULL, NULL}
1380 };
1381 
1382 static PyMemberDef wrapper_members[] = {
1383     {"__self__", _Py_T_OBJECT, offsetof(wrapperobject, self), Py_READONLY},
1384     {0}
1385 };
1386 
1387 static PyObject *
wrapper_objclass(PyObject * wp,void * Py_UNUSED (ignored))1388 wrapper_objclass(PyObject *wp, void *Py_UNUSED(ignored))
1389 {
1390     PyObject *c = (PyObject *)PyDescr_TYPE(((wrapperobject *)wp)->descr);
1391 
1392     return Py_NewRef(c);
1393 }
1394 
1395 static PyObject *
wrapper_name(PyObject * wp,void * Py_UNUSED (ignored))1396 wrapper_name(PyObject *wp, void *Py_UNUSED(ignored))
1397 {
1398     const char *s = ((wrapperobject *)wp)->descr->d_base->name;
1399 
1400     return PyUnicode_FromString(s);
1401 }
1402 
1403 static PyObject *
wrapper_doc(PyObject * self,void * Py_UNUSED (ignored))1404 wrapper_doc(PyObject *self, void *Py_UNUSED(ignored))
1405 {
1406     wrapperobject *wp = (wrapperobject *)self;
1407     return _PyType_GetDocFromInternalDoc(wp->descr->d_base->name, wp->descr->d_base->doc);
1408 }
1409 
1410 static PyObject *
wrapper_text_signature(PyObject * self,void * Py_UNUSED (ignored))1411 wrapper_text_signature(PyObject *self, void *Py_UNUSED(ignored))
1412 {
1413     wrapperobject *wp = (wrapperobject *)self;
1414     return _PyType_GetTextSignatureFromInternalDoc(wp->descr->d_base->name,
1415                                                    wp->descr->d_base->doc, 0);
1416 }
1417 
1418 static PyObject *
wrapper_qualname(PyObject * self,void * Py_UNUSED (ignored))1419 wrapper_qualname(PyObject *self, void *Py_UNUSED(ignored))
1420 {
1421     wrapperobject *wp = (wrapperobject *)self;
1422     return descr_get_qualname((PyObject *)wp->descr, NULL);
1423 }
1424 
1425 static PyGetSetDef wrapper_getsets[] = {
1426     {"__objclass__", wrapper_objclass},
1427     {"__name__", wrapper_name},
1428     {"__qualname__", wrapper_qualname},
1429     {"__doc__", wrapper_doc},
1430     {"__text_signature__", wrapper_text_signature},
1431     {0}
1432 };
1433 
1434 static PyObject *
wrapper_call(PyObject * self,PyObject * args,PyObject * kwds)1435 wrapper_call(PyObject *self, PyObject *args, PyObject *kwds)
1436 {
1437     wrapperobject *wp = (wrapperobject *)self;
1438     return wrapperdescr_raw_call(wp->descr, wp->self, args, kwds);
1439 }
1440 
1441 static int
wrapper_traverse(PyObject * self,visitproc visit,void * arg)1442 wrapper_traverse(PyObject *self, visitproc visit, void *arg)
1443 {
1444     wrapperobject *wp = (wrapperobject *)self;
1445     Py_VISIT(wp->descr);
1446     Py_VISIT(wp->self);
1447     return 0;
1448 }
1449 
1450 PyTypeObject _PyMethodWrapper_Type = {
1451     PyVarObject_HEAD_INIT(&PyType_Type, 0)
1452     "method-wrapper",                           /* tp_name */
1453     sizeof(wrapperobject),                      /* tp_basicsize */
1454     0,                                          /* tp_itemsize */
1455     /* methods */
1456     wrapper_dealloc,                            /* tp_dealloc */
1457     0,                                          /* tp_vectorcall_offset */
1458     0,                                          /* tp_getattr */
1459     0,                                          /* tp_setattr */
1460     0,                                          /* tp_as_async */
1461     wrapper_repr,                               /* tp_repr */
1462     0,                                          /* tp_as_number */
1463     0,                                          /* tp_as_sequence */
1464     0,                                          /* tp_as_mapping */
1465     wrapper_hash,                               /* tp_hash */
1466     wrapper_call,                               /* tp_call */
1467     0,                                          /* tp_str */
1468     PyObject_GenericGetAttr,                    /* tp_getattro */
1469     0,                                          /* tp_setattro */
1470     0,                                          /* tp_as_buffer */
1471     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1472     0,                                          /* tp_doc */
1473     wrapper_traverse,                           /* tp_traverse */
1474     0,                                          /* tp_clear */
1475     wrapper_richcompare,                        /* tp_richcompare */
1476     0,                                          /* tp_weaklistoffset */
1477     0,                                          /* tp_iter */
1478     0,                                          /* tp_iternext */
1479     wrapper_methods,                            /* tp_methods */
1480     wrapper_members,                            /* tp_members */
1481     wrapper_getsets,                            /* tp_getset */
1482     0,                                          /* tp_base */
1483     0,                                          /* tp_dict */
1484     0,                                          /* tp_descr_get */
1485     0,                                          /* tp_descr_set */
1486 };
1487 
1488 PyObject *
PyWrapper_New(PyObject * d,PyObject * self)1489 PyWrapper_New(PyObject *d, PyObject *self)
1490 {
1491     wrapperobject *wp;
1492     PyWrapperDescrObject *descr;
1493 
1494     assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type));
1495     descr = (PyWrapperDescrObject *)d;
1496     assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
1497                                     (PyObject *)PyDescr_TYPE(descr)));
1498 
1499     wp = PyObject_GC_New(wrapperobject, &_PyMethodWrapper_Type);
1500     if (wp != NULL) {
1501         wp->descr = (PyWrapperDescrObject*)Py_NewRef(descr);
1502         wp->self = Py_NewRef(self);
1503         _PyObject_GC_TRACK(wp);
1504     }
1505     return (PyObject *)wp;
1506 }
1507 
1508 
1509 /* A built-in 'property' type */
1510 
1511 /*
1512 class property(object):
1513 
1514     def __init__(self, fget=None, fset=None, fdel=None, doc=None):
1515         if doc is None and fget is not None and hasattr(fget, "__doc__"):
1516             doc = fget.__doc__
1517         self.__get = fget
1518         self.__set = fset
1519         self.__del = fdel
1520         try:
1521             self.__doc__ = doc
1522         except AttributeError:  # read-only or dict-less class
1523             pass
1524         self.__name = None
1525 
1526     def __set_name__(self, owner, name):
1527         self.__name = name
1528 
1529     @property
1530     def __name__(self):
1531         return self.__name if self.__name is not None else self.fget.__name__
1532 
1533     @__name__.setter
1534     def __name__(self, value):
1535         self.__name = value
1536 
1537     def __get__(self, inst, type=None):
1538         if inst is None:
1539             return self
1540         if self.__get is None:
1541             raise AttributeError("property has no getter")
1542         return self.__get(inst)
1543 
1544     def __set__(self, inst, value):
1545         if self.__set is None:
1546             raise AttributeError("property has no setter")
1547         return self.__set(inst, value)
1548 
1549     def __delete__(self, inst):
1550         if self.__del is None:
1551             raise AttributeError("property has no deleter")
1552         return self.__del(inst)
1553 
1554 */
1555 
1556 static PyObject * property_copy(PyObject *, PyObject *, PyObject *,
1557                                   PyObject *);
1558 
1559 static PyMemberDef property_members[] = {
1560     {"fget", _Py_T_OBJECT, offsetof(propertyobject, prop_get), Py_READONLY},
1561     {"fset", _Py_T_OBJECT, offsetof(propertyobject, prop_set), Py_READONLY},
1562     {"fdel", _Py_T_OBJECT, offsetof(propertyobject, prop_del), Py_READONLY},
1563     {"__doc__",  _Py_T_OBJECT, offsetof(propertyobject, prop_doc), 0},
1564     {0}
1565 };
1566 
1567 
1568 PyDoc_STRVAR(getter_doc,
1569              "Descriptor to obtain a copy of the property with a different getter.");
1570 
1571 static PyObject *
property_getter(PyObject * self,PyObject * getter)1572 property_getter(PyObject *self, PyObject *getter)
1573 {
1574     return property_copy(self, getter, NULL, NULL);
1575 }
1576 
1577 
1578 PyDoc_STRVAR(setter_doc,
1579              "Descriptor to obtain a copy of the property with a different setter.");
1580 
1581 static PyObject *
property_setter(PyObject * self,PyObject * setter)1582 property_setter(PyObject *self, PyObject *setter)
1583 {
1584     return property_copy(self, NULL, setter, NULL);
1585 }
1586 
1587 
1588 PyDoc_STRVAR(deleter_doc,
1589              "Descriptor to obtain a copy of the property with a different deleter.");
1590 
1591 static PyObject *
property_deleter(PyObject * self,PyObject * deleter)1592 property_deleter(PyObject *self, PyObject *deleter)
1593 {
1594     return property_copy(self, NULL, NULL, deleter);
1595 }
1596 
1597 
1598 PyDoc_STRVAR(set_name_doc,
1599              "__set_name__($self, owner, name, /)\n"
1600              "--\n"
1601              "\n"
1602              "Method to set name of a property.");
1603 
1604 static PyObject *
property_set_name(PyObject * self,PyObject * args)1605 property_set_name(PyObject *self, PyObject *args) {
1606     if (PyTuple_GET_SIZE(args) != 2) {
1607         PyErr_Format(
1608                 PyExc_TypeError,
1609                 "__set_name__() takes 2 positional arguments but %d were given",
1610                 PyTuple_GET_SIZE(args));
1611         return NULL;
1612     }
1613 
1614     propertyobject *prop = (propertyobject *)self;
1615     PyObject *name = PyTuple_GET_ITEM(args, 1);
1616 
1617     Py_XSETREF(prop->prop_name, Py_XNewRef(name));
1618 
1619     Py_RETURN_NONE;
1620 }
1621 
1622 static PyMethodDef property_methods[] = {
1623     {"getter", property_getter, METH_O, getter_doc},
1624     {"setter", property_setter, METH_O, setter_doc},
1625     {"deleter", property_deleter, METH_O, deleter_doc},
1626     {"__set_name__", property_set_name, METH_VARARGS, set_name_doc},
1627     {0}
1628 };
1629 
1630 
1631 static void
property_dealloc(PyObject * self)1632 property_dealloc(PyObject *self)
1633 {
1634     propertyobject *gs = (propertyobject *)self;
1635 
1636     _PyObject_GC_UNTRACK(self);
1637     Py_XDECREF(gs->prop_get);
1638     Py_XDECREF(gs->prop_set);
1639     Py_XDECREF(gs->prop_del);
1640     Py_XDECREF(gs->prop_doc);
1641     Py_XDECREF(gs->prop_name);
1642     Py_TYPE(self)->tp_free(self);
1643 }
1644 
1645 static int
property_name(propertyobject * prop,PyObject ** name)1646 property_name(propertyobject *prop, PyObject **name)
1647 {
1648     if (prop->prop_name != NULL) {
1649         *name = Py_NewRef(prop->prop_name);
1650         return 1;
1651     }
1652     if (prop->prop_get == NULL) {
1653         *name = NULL;
1654         return 0;
1655     }
1656     return PyObject_GetOptionalAttr(prop->prop_get, &_Py_ID(__name__), name);
1657 }
1658 
1659 static PyObject *
property_descr_get(PyObject * self,PyObject * obj,PyObject * type)1660 property_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1661 {
1662     if (obj == NULL || obj == Py_None) {
1663         return Py_NewRef(self);
1664     }
1665 
1666     propertyobject *gs = (propertyobject *)self;
1667     if (gs->prop_get == NULL) {
1668         PyObject *propname;
1669         if (property_name(gs, &propname) < 0) {
1670             return NULL;
1671         }
1672         PyObject *qualname = PyType_GetQualName(Py_TYPE(obj));
1673         if (propname != NULL && qualname != NULL) {
1674             PyErr_Format(PyExc_AttributeError,
1675                          "property %R of %R object has no getter",
1676                          propname,
1677                          qualname);
1678         }
1679         else if (qualname != NULL) {
1680             PyErr_Format(PyExc_AttributeError,
1681                          "property of %R object has no getter",
1682                          qualname);
1683         } else {
1684             PyErr_SetString(PyExc_AttributeError,
1685                             "property has no getter");
1686         }
1687         Py_XDECREF(propname);
1688         Py_XDECREF(qualname);
1689         return NULL;
1690     }
1691 
1692     return PyObject_CallOneArg(gs->prop_get, obj);
1693 }
1694 
1695 static int
property_descr_set(PyObject * self,PyObject * obj,PyObject * value)1696 property_descr_set(PyObject *self, PyObject *obj, PyObject *value)
1697 {
1698     propertyobject *gs = (propertyobject *)self;
1699     PyObject *func, *res;
1700 
1701     if (value == NULL) {
1702         func = gs->prop_del;
1703     }
1704     else {
1705         func = gs->prop_set;
1706     }
1707 
1708     if (func == NULL) {
1709         PyObject *propname;
1710         if (property_name(gs, &propname) < 0) {
1711             return -1;
1712         }
1713         PyObject *qualname = NULL;
1714         if (obj != NULL) {
1715             qualname = PyType_GetQualName(Py_TYPE(obj));
1716         }
1717         if (propname != NULL && qualname != NULL) {
1718             PyErr_Format(PyExc_AttributeError,
1719                         value == NULL ?
1720                         "property %R of %R object has no deleter" :
1721                         "property %R of %R object has no setter",
1722                         propname,
1723                         qualname);
1724         }
1725         else if (qualname != NULL) {
1726             PyErr_Format(PyExc_AttributeError,
1727                             value == NULL ?
1728                             "property of %R object has no deleter" :
1729                             "property of %R object has no setter",
1730                             qualname);
1731         }
1732         else {
1733             PyErr_SetString(PyExc_AttributeError,
1734                          value == NULL ?
1735                          "property has no deleter" :
1736                          "property has no setter");
1737         }
1738         Py_XDECREF(propname);
1739         Py_XDECREF(qualname);
1740         return -1;
1741     }
1742 
1743     if (value == NULL) {
1744         res = PyObject_CallOneArg(func, obj);
1745     }
1746     else {
1747         EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_API, func);
1748         PyObject *args[] = { obj, value };
1749         res = PyObject_Vectorcall(func, args, 2, NULL);
1750     }
1751 
1752     if (res == NULL) {
1753         return -1;
1754     }
1755 
1756     Py_DECREF(res);
1757     return 0;
1758 }
1759 
1760 static PyObject *
property_copy(PyObject * old,PyObject * get,PyObject * set,PyObject * del)1761 property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *del)
1762 {
1763     propertyobject *pold = (propertyobject *)old;
1764     PyObject *new, *type, *doc;
1765 
1766     type = PyObject_Type(old);
1767     if (type == NULL)
1768         return NULL;
1769 
1770     if (get == NULL || get == Py_None) {
1771         get = pold->prop_get ? pold->prop_get : Py_None;
1772     }
1773     if (set == NULL || set == Py_None) {
1774         set = pold->prop_set ? pold->prop_set : Py_None;
1775     }
1776     if (del == NULL || del == Py_None) {
1777         del = pold->prop_del ? pold->prop_del : Py_None;
1778     }
1779     if (pold->getter_doc && get != Py_None) {
1780         /* make _init use __doc__ from getter */
1781         doc = Py_None;
1782     }
1783     else {
1784         doc = pold->prop_doc ? pold->prop_doc : Py_None;
1785     }
1786 
1787     new =  PyObject_CallFunctionObjArgs(type, get, set, del, doc, NULL);
1788     Py_DECREF(type);
1789     if (new == NULL)
1790         return NULL;
1791 
1792     if (PyObject_TypeCheck((new), &PyProperty_Type)) {
1793         Py_XSETREF(((propertyobject *) new)->prop_name, Py_XNewRef(pold->prop_name));
1794     }
1795     return new;
1796 }
1797 
1798 /*[clinic input]
1799 property.__init__ as property_init
1800 
1801     fget: object(c_default="NULL") = None
1802         function to be used for getting an attribute value
1803     fset: object(c_default="NULL") = None
1804         function to be used for setting an attribute value
1805     fdel: object(c_default="NULL") = None
1806         function to be used for del'ing an attribute
1807     doc: object(c_default="NULL") = None
1808         docstring
1809 
1810 Property attribute.
1811 
1812 Typical use is to define a managed attribute x:
1813 
1814 class C(object):
1815     def getx(self): return self._x
1816     def setx(self, value): self._x = value
1817     def delx(self): del self._x
1818     x = property(getx, setx, delx, "I'm the 'x' property.")
1819 
1820 Decorators make defining new properties or modifying existing ones easy:
1821 
1822 class C(object):
1823     @property
1824     def x(self):
1825         "I am the 'x' property."
1826         return self._x
1827     @x.setter
1828     def x(self, value):
1829         self._x = value
1830     @x.deleter
1831     def x(self):
1832         del self._x
1833 [clinic start generated code]*/
1834 
1835 static int
property_init_impl(propertyobject * self,PyObject * fget,PyObject * fset,PyObject * fdel,PyObject * doc)1836 property_init_impl(propertyobject *self, PyObject *fget, PyObject *fset,
1837                    PyObject *fdel, PyObject *doc)
1838 /*[clinic end generated code: output=01a960742b692b57 input=dfb5dbbffc6932d5]*/
1839 {
1840     if (fget == Py_None)
1841         fget = NULL;
1842     if (fset == Py_None)
1843         fset = NULL;
1844     if (fdel == Py_None)
1845         fdel = NULL;
1846 
1847     Py_XSETREF(self->prop_get, Py_XNewRef(fget));
1848     Py_XSETREF(self->prop_set, Py_XNewRef(fset));
1849     Py_XSETREF(self->prop_del, Py_XNewRef(fdel));
1850     Py_XSETREF(self->prop_doc, NULL);
1851     Py_XSETREF(self->prop_name, NULL);
1852 
1853     self->getter_doc = 0;
1854     PyObject *prop_doc = NULL;
1855 
1856     if (doc != NULL && doc != Py_None) {
1857         prop_doc = Py_XNewRef(doc);
1858     }
1859     /* if no docstring given and the getter has one, use that one */
1860     else if (fget != NULL) {
1861         int rc = PyObject_GetOptionalAttr(fget, &_Py_ID(__doc__), &prop_doc);
1862         if (rc < 0) {
1863             return rc;
1864         }
1865         if (prop_doc == Py_None) {
1866             prop_doc = NULL;
1867             Py_DECREF(Py_None);
1868         }
1869         if (prop_doc != NULL){
1870             self->getter_doc = 1;
1871         }
1872     }
1873 
1874     /* At this point `prop_doc` is either NULL or
1875        a non-None object with incremented ref counter */
1876 
1877     if (Py_IS_TYPE(self, &PyProperty_Type)) {
1878         Py_XSETREF(self->prop_doc, prop_doc);
1879     } else {
1880         /* If this is a property subclass, put __doc__ in the dict
1881            or designated slot of the subclass instance instead, otherwise
1882            it gets shadowed by __doc__ in the class's dict. */
1883 
1884         if (prop_doc == NULL) {
1885             prop_doc = Py_NewRef(Py_None);
1886         }
1887         int err = PyObject_SetAttr(
1888                     (PyObject *)self, &_Py_ID(__doc__), prop_doc);
1889         Py_DECREF(prop_doc);
1890         if (err < 0) {
1891             assert(PyErr_Occurred());
1892             if (!self->getter_doc &&
1893                 PyErr_ExceptionMatches(PyExc_AttributeError))
1894             {
1895                 PyErr_Clear();
1896                 // https://github.com/python/cpython/issues/98963#issuecomment-1574413319
1897                 // Python silently dropped this doc assignment through 3.11.
1898                 // We preserve that behavior for backwards compatibility.
1899                 //
1900                 // If we ever want to deprecate this behavior, only raise a
1901                 // warning or error when proc_doc is not None so that
1902                 // property without a specific doc= still works.
1903                 return 0;
1904             } else {
1905                 return -1;
1906             }
1907         }
1908     }
1909 
1910     return 0;
1911 }
1912 
1913 static PyObject *
property_get__name__(propertyobject * prop,void * Py_UNUSED (ignored))1914 property_get__name__(propertyobject *prop, void *Py_UNUSED(ignored))
1915 {
1916     PyObject *name;
1917     if (property_name(prop, &name) < 0) {
1918         return NULL;
1919     }
1920     if (name == NULL) {
1921         PyErr_SetString(PyExc_AttributeError,
1922                         "'property' object has no attribute '__name__'");
1923     }
1924     return name;
1925 }
1926 
1927 static int
property_set__name__(propertyobject * prop,PyObject * value,void * Py_UNUSED (ignored))1928 property_set__name__(propertyobject *prop, PyObject *value,
1929                      void *Py_UNUSED(ignored))
1930 {
1931     Py_XSETREF(prop->prop_name, Py_XNewRef(value));
1932     return 0;
1933 }
1934 
1935 static PyObject *
property_get___isabstractmethod__(propertyobject * prop,void * closure)1936 property_get___isabstractmethod__(propertyobject *prop, void *closure)
1937 {
1938     int res = _PyObject_IsAbstract(prop->prop_get);
1939     if (res == -1) {
1940         return NULL;
1941     }
1942     else if (res) {
1943         Py_RETURN_TRUE;
1944     }
1945 
1946     res = _PyObject_IsAbstract(prop->prop_set);
1947     if (res == -1) {
1948         return NULL;
1949     }
1950     else if (res) {
1951         Py_RETURN_TRUE;
1952     }
1953 
1954     res = _PyObject_IsAbstract(prop->prop_del);
1955     if (res == -1) {
1956         return NULL;
1957     }
1958     else if (res) {
1959         Py_RETURN_TRUE;
1960     }
1961     Py_RETURN_FALSE;
1962 }
1963 
1964 static PyGetSetDef property_getsetlist[] = {
1965     {"__name__", (getter)property_get__name__, (setter)property_set__name__},
1966     {"__isabstractmethod__",
1967      (getter)property_get___isabstractmethod__, NULL,
1968      NULL,
1969      NULL},
1970     {NULL} /* Sentinel */
1971 };
1972 
1973 static int
property_traverse(PyObject * self,visitproc visit,void * arg)1974 property_traverse(PyObject *self, visitproc visit, void *arg)
1975 {
1976     propertyobject *pp = (propertyobject *)self;
1977     Py_VISIT(pp->prop_get);
1978     Py_VISIT(pp->prop_set);
1979     Py_VISIT(pp->prop_del);
1980     Py_VISIT(pp->prop_doc);
1981     Py_VISIT(pp->prop_name);
1982     return 0;
1983 }
1984 
1985 static int
property_clear(PyObject * self)1986 property_clear(PyObject *self)
1987 {
1988     propertyobject *pp = (propertyobject *)self;
1989     Py_CLEAR(pp->prop_doc);
1990     return 0;
1991 }
1992 
1993 #include "clinic/descrobject.c.h"
1994 
1995 PyTypeObject PyDictProxy_Type = {
1996     PyVarObject_HEAD_INIT(&PyType_Type, 0)
1997     "mappingproxy",                             /* tp_name */
1998     sizeof(mappingproxyobject),                 /* tp_basicsize */
1999     0,                                          /* tp_itemsize */
2000     /* methods */
2001     mappingproxy_dealloc,                       /* tp_dealloc */
2002     0,                                          /* tp_vectorcall_offset */
2003     0,                                          /* tp_getattr */
2004     0,                                          /* tp_setattr */
2005     0,                                          /* tp_as_async */
2006     mappingproxy_repr,                          /* tp_repr */
2007     &mappingproxy_as_number,                    /* tp_as_number */
2008     &mappingproxy_as_sequence,                  /* tp_as_sequence */
2009     &mappingproxy_as_mapping,                   /* tp_as_mapping */
2010     mappingproxy_hash,                          /* tp_hash */
2011     0,                                          /* tp_call */
2012     mappingproxy_str,                           /* tp_str */
2013     PyObject_GenericGetAttr,                    /* tp_getattro */
2014     0,                                          /* tp_setattro */
2015     0,                                          /* tp_as_buffer */
2016     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
2017         Py_TPFLAGS_MAPPING,                     /* tp_flags */
2018     mappingproxy_new__doc__,                    /* tp_doc */
2019     mappingproxy_traverse,                      /* tp_traverse */
2020     0,                                          /* tp_clear */
2021     mappingproxy_richcompare,                   /* tp_richcompare */
2022     0,                                          /* tp_weaklistoffset */
2023     mappingproxy_getiter,                       /* tp_iter */
2024     0,                                          /* tp_iternext */
2025     mappingproxy_methods,                       /* tp_methods */
2026     0,                                          /* tp_members */
2027     0,                                          /* tp_getset */
2028     0,                                          /* tp_base */
2029     0,                                          /* tp_dict */
2030     0,                                          /* tp_descr_get */
2031     0,                                          /* tp_descr_set */
2032     0,                                          /* tp_dictoffset */
2033     0,                                          /* tp_init */
2034     0,                                          /* tp_alloc */
2035     mappingproxy_new,                           /* tp_new */
2036 };
2037 
2038 PyTypeObject PyProperty_Type = {
2039     PyVarObject_HEAD_INIT(&PyType_Type, 0)
2040     "property",                                 /* tp_name */
2041     sizeof(propertyobject),                     /* tp_basicsize */
2042     0,                                          /* tp_itemsize */
2043     /* methods */
2044     property_dealloc,                           /* tp_dealloc */
2045     0,                                          /* tp_vectorcall_offset */
2046     0,                                          /* tp_getattr */
2047     0,                                          /* tp_setattr */
2048     0,                                          /* tp_as_async */
2049     0,                                          /* tp_repr */
2050     0,                                          /* tp_as_number */
2051     0,                                          /* tp_as_sequence */
2052     0,                                          /* tp_as_mapping */
2053     0,                                          /* tp_hash */
2054     0,                                          /* tp_call */
2055     0,                                          /* tp_str */
2056     PyObject_GenericGetAttr,                    /* tp_getattro */
2057     0,                                          /* tp_setattro */
2058     0,                                          /* tp_as_buffer */
2059     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
2060         Py_TPFLAGS_BASETYPE,                    /* tp_flags */
2061     property_init__doc__,                       /* tp_doc */
2062     property_traverse,                          /* tp_traverse */
2063     property_clear,                             /* tp_clear */
2064     0,                                          /* tp_richcompare */
2065     0,                                          /* tp_weaklistoffset */
2066     0,                                          /* tp_iter */
2067     0,                                          /* tp_iternext */
2068     property_methods,                           /* tp_methods */
2069     property_members,                           /* tp_members */
2070     property_getsetlist,                        /* tp_getset */
2071     0,                                          /* tp_base */
2072     0,                                          /* tp_dict */
2073     property_descr_get,                         /* tp_descr_get */
2074     property_descr_set,                         /* tp_descr_set */
2075     0,                                          /* tp_dictoffset */
2076     property_init,                              /* tp_init */
2077     PyType_GenericAlloc,                        /* tp_alloc */
2078     PyType_GenericNew,                          /* tp_new */
2079     PyObject_GC_Del,                            /* tp_free */
2080 };
2081