LCOV - code coverage report
Current view: top level - Objects - descrobject.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 168 458 36.7 %
Date: 2017-04-19 Functions: 27 69 39.1 %

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

Generated by: LCOV version 1.10