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 descr_dealloc(PyDescrObject *descr) 8 { 9 _PyObject_GC_UNTRACK(descr); 10 Py_XDECREF(descr->d_type); 11 Py_XDECREF(descr->d_name); 12 PyObject_GC_Del(descr); 13 } 14 15 static char * 16 descr_name(PyDescrObject *descr) 17 { 18 if (descr->d_name != NULL && PyString_Check(descr->d_name)) 19 return PyString_AS_STRING(descr->d_name); 20 else 21 return "?"; 22 } 23 24 static PyObject * 25 descr_repr(PyDescrObject *descr, char *format) 26 { 27 return PyString_FromFormat(format, descr_name(descr), 28 descr->d_type->tp_name); 29 } 30 31 static PyObject * 32 method_repr(PyMethodDescrObject *descr) 33 { 34 return descr_repr((PyDescrObject *)descr, 35 "<method '%s' of '%s' objects>"); 36 } 37 38 static PyObject * 39 member_repr(PyMemberDescrObject *descr) 40 { 41 return descr_repr((PyDescrObject *)descr, 42 "<member '%s' of '%s' objects>"); 43 } 44 45 static PyObject * 46 getset_repr(PyGetSetDescrObject *descr) 47 { 48 return descr_repr((PyDescrObject *)descr, 49 "<attribute '%s' of '%s' objects>"); 50 } 51 52 static PyObject * 53 wrapperdescr_repr(PyWrapperDescrObject *descr) 54 { 55 return descr_repr((PyDescrObject *)descr, 56 "<slot wrapper '%s' of '%s' objects>"); 57 } 58 59 static int 60 descr_check(PyDescrObject *descr, PyObject *obj, PyObject **pres) 61 { 62 if (obj == NULL) { 63 Py_INCREF(descr); 64 *pres = (PyObject *)descr; 65 return 1; 66 } 67 if (!PyObject_TypeCheck(obj, descr->d_type)) { 68 PyErr_Format(PyExc_TypeError, 69 "descriptor '%s' for '%s' objects " 70 "doesn't apply to '%s' object", 71 descr_name((PyDescrObject *)descr), 72 descr->d_type->tp_name, 73 obj->ob_type->tp_name); 74 *pres = NULL; 75 return 1; 76 } 77 return 0; 78 } 79 80 static PyObject * 81 classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) 82 { 83 /* Ensure a valid type. Class methods ignore obj. */ 84 if (type == NULL) { 85 if (obj != NULL) 86 type = (PyObject *)obj->ob_type; 87 else { 88 /* Wot - no type?! */ 89 PyErr_Format(PyExc_TypeError, 90 "descriptor '%s' for type '%s' " 91 "needs either an object or a type", 92 descr_name((PyDescrObject *)descr), 93 descr->d_type->tp_name); 94 return NULL; 95 } 96 } 97 if (!PyType_Check(type)) { 98 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 descr->d_type->tp_name, 103 type->ob_type->tp_name); 104 return NULL; 105 } 106 if (!PyType_IsSubtype((PyTypeObject *)type, descr->d_type)) { 107 PyErr_Format(PyExc_TypeError, 108 "descriptor '%s' for type '%s' " 109 "doesn't apply to type '%s'", 110 descr_name((PyDescrObject *)descr), 111 descr->d_type->tp_name, 112 ((PyTypeObject *)type)->tp_name); 113 return NULL; 114 } 115 return PyCFunction_New(descr->d_method, type); 116 } 117 118 static PyObject * 119 method_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) 120 { 121 PyObject *res; 122 123 if (descr_check((PyDescrObject *)descr, obj, &res)) 124 return res; 125 return PyCFunction_New(descr->d_method, obj); 126 } 127 128 static PyObject * 129 member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type) 130 { 131 PyObject *res; 132 133 if (descr_check((PyDescrObject *)descr, obj, &res)) 134 return res; 135 return PyMember_GetOne((char *)obj, descr->d_member); 136 } 137 138 static PyObject * 139 getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type) 140 { 141 PyObject *res; 142 143 if (descr_check((PyDescrObject *)descr, obj, &res)) 144 return res; 145 if (descr->d_getset->get != NULL) 146 return descr->d_getset->get(obj, descr->d_getset->closure); 147 PyErr_Format(PyExc_AttributeError, 148 "attribute '%.300s' of '%.100s' objects is not readable", 149 descr_name((PyDescrObject *)descr), 150 descr->d_type->tp_name); 151 return NULL; 152 } 153 154 static PyObject * 155 wrapperdescr_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type) 156 { 157 PyObject *res; 158 159 if (descr_check((PyDescrObject *)descr, obj, &res)) 160 return res; 161 return PyWrapper_New((PyObject *)descr, obj); 162 } 163 164 static int 165 descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value, 166 int *pres) 167 { 168 assert(obj != NULL); 169 if (!PyObject_TypeCheck(obj, descr->d_type)) { 170 PyErr_Format(PyExc_TypeError, 171 "descriptor '%.200s' for '%.100s' objects " 172 "doesn't apply to '%.100s' object", 173 descr_name(descr), 174 descr->d_type->tp_name, 175 obj->ob_type->tp_name); 176 *pres = -1; 177 return 1; 178 } 179 return 0; 180 } 181 182 static int 183 member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value) 184 { 185 int res; 186 187 if (descr_setcheck((PyDescrObject *)descr, obj, value, &res)) 188 return res; 189 return PyMember_SetOne((char *)obj, descr->d_member, value); 190 } 191 192 static int 193 getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) 194 { 195 int res; 196 197 if (descr_setcheck((PyDescrObject *)descr, obj, value, &res)) 198 return res; 199 if (descr->d_getset->set != NULL) 200 return descr->d_getset->set(obj, value, 201 descr->d_getset->closure); 202 PyErr_Format(PyExc_AttributeError, 203 "attribute '%.300s' of '%.100s' objects is not writable", 204 descr_name((PyDescrObject *)descr), 205 descr->d_type->tp_name); 206 return -1; 207 } 208 209 static PyObject * 210 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 argc = PyTuple_GET_SIZE(args); 218 if (argc < 1) { 219 PyErr_Format(PyExc_TypeError, 220 "descriptor '%.300s' of '%.100s' " 221 "object needs an argument", 222 descr_name((PyDescrObject *)descr), 223 descr->d_type->tp_name); 224 return NULL; 225 } 226 self = PyTuple_GET_ITEM(args, 0); 227 if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), 228 (PyObject *)(descr->d_type))) { 229 PyErr_Format(PyExc_TypeError, 230 "descriptor '%.200s' " 231 "requires a '%.100s' object " 232 "but received a '%.100s'", 233 descr_name((PyDescrObject *)descr), 234 descr->d_type->tp_name, 235 self->ob_type->tp_name); 236 return NULL; 237 } 238 239 func = PyCFunction_New(descr->d_method, self); 240 if (func == NULL) 241 return NULL; 242 args = PyTuple_GetSlice(args, 1, argc); 243 if (args == NULL) { 244 Py_DECREF(func); 245 return NULL; 246 } 247 result = PyEval_CallObjectWithKeywords(func, args, kwds); 248 Py_DECREF(args); 249 Py_DECREF(func); 250 return result; 251 } 252 253 static PyObject * 254 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 argc = PyTuple_GET_SIZE(args); 263 if (argc < 1) { 264 PyErr_Format(PyExc_TypeError, 265 "descriptor '%s' of '%.100s' " 266 "object needs an argument", 267 descr_name((PyDescrObject *)descr), 268 descr->d_type->tp_name); 269 return NULL; 270 } 271 self = PyTuple_GET_ITEM(args, 0); 272 if (!PyType_Check(self)) { 273 PyErr_Format(PyExc_TypeError, 274 "descriptor '%s' requires a type " 275 "but received a '%.100s'", 276 descr_name((PyDescrObject *)descr), 277 self->ob_type->tp_name); 278 return NULL; 279 } 280 if (!PyType_IsSubtype((PyTypeObject *)self, descr->d_type)) { 281 PyErr_Format(PyExc_TypeError, 282 "descriptor '%s' " 283 "requires a subtype of '%.100s' " 284 "but received '%.100s", 285 descr_name((PyDescrObject *)descr), 286 descr->d_type->tp_name, 287 self->ob_type->tp_name); 288 return NULL; 289 } 290 291 func = PyCFunction_New(descr->d_method, self); 292 if (func == NULL) 293 return NULL; 294 args = PyTuple_GetSlice(args, 1, argc); 295 if (args == NULL) { 296 Py_DECREF(func); 297 return NULL; 298 } 299 result = PyEval_CallObjectWithKeywords(func, args, kwds); 300 Py_DECREF(func); 301 Py_DECREF(args); 302 return result; 303 } 304 305 static PyObject * 306 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 argc = PyTuple_GET_SIZE(args); 314 if (argc < 1) { 315 PyErr_Format(PyExc_TypeError, 316 "descriptor '%.300s' of '%.100s' " 317 "object needs an argument", 318 descr_name((PyDescrObject *)descr), 319 descr->d_type->tp_name); 320 return NULL; 321 } 322 self = PyTuple_GET_ITEM(args, 0); 323 if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), 324 (PyObject *)(descr->d_type))) { 325 PyErr_Format(PyExc_TypeError, 326 "descriptor '%.200s' " 327 "requires a '%.100s' object " 328 "but received a '%.100s'", 329 descr_name((PyDescrObject *)descr), 330 descr->d_type->tp_name, 331 self->ob_type->tp_name); 332 return NULL; 333 } 334 335 func = PyWrapper_New((PyObject *)descr, self); 336 if (func == NULL) 337 return NULL; 338 args = PyTuple_GetSlice(args, 1, argc); 339 if (args == NULL) { 340 Py_DECREF(func); 341 return NULL; 342 } 343 result = PyEval_CallObjectWithKeywords(func, args, kwds); 344 Py_DECREF(args); 345 Py_DECREF(func); 346 return result; 347 } 348 349 static PyObject * 350 method_get_doc(PyMethodDescrObject *descr, void *closure) 351 { 352 if (descr->d_method->ml_doc == NULL) { 353 Py_INCREF(Py_None); 354 return Py_None; 355 } 356 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 member_get_doc(PyMemberDescrObject *descr, void *closure) 372 { 373 if (descr->d_member->doc == NULL) { 374 Py_INCREF(Py_None); 375 return Py_None; 376 } 377 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 getset_get_doc(PyGetSetDescrObject *descr, void *closure) 387 { 388 if (descr->d_getset->doc == NULL) { 389 Py_INCREF(Py_None); 390 return Py_None; 391 } 392 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 wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure) 402 { 403 if (descr->d_base->doc == NULL) { 404 Py_INCREF(Py_None); 405 return Py_None; 406 } 407 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 descr_traverse(PyObject *self, visitproc visit, void *arg) 417 { 418 PyDescrObject *descr = (PyDescrObject *)self; 419 Py_VISIT(descr->d_type); 420 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 descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name) 611 { 612 PyDescrObject *descr; 613 614 descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0); 615 if (descr != NULL) { 616 Py_XINCREF(type); 617 descr->d_type = type; 618 descr->d_name = PyString_InternFromString(name); 619 if (descr->d_name == NULL) { 620 Py_DECREF(descr); 621 descr = NULL; 622 } 623 } 624 return descr; 625 } 626 627 PyObject * 628 PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method) 629 { 630 PyMethodDescrObject *descr; 631 632 descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type, 633 type, method->ml_name); 634 if (descr != NULL) 635 descr->d_method = method; 636 return (PyObject *)descr; 637 } 638 639 PyObject * 640 PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method) 641 { 642 PyMethodDescrObject *descr; 643 644 descr = (PyMethodDescrObject *)descr_new(&PyClassMethodDescr_Type, 645 type, method->ml_name); 646 if (descr != NULL) 647 descr->d_method = method; 648 return (PyObject *)descr; 649 } 650 651 PyObject * 652 PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member) 653 { 654 PyMemberDescrObject *descr; 655 656 descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type, 657 type, member->name); 658 if (descr != NULL) 659 descr->d_member = member; 660 return (PyObject *)descr; 661 } 662 663 PyObject * 664 PyDescr_NewGetSet(PyTypeObject *type, PyGetSetDef *getset) 665 { 666 PyGetSetDescrObject *descr; 667 668 descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type, 669 type, getset->name); 670 if (descr != NULL) 671 descr->d_getset = getset; 672 return (PyObject *)descr; 673 } 674 675 PyObject * 676 PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) 677 { 678 PyWrapperDescrObject *descr; 679 680 descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type, 681 type, base->name); 682 if (descr != NULL) { 683 descr->d_base = base; 684 descr->d_wrapped = wrapped; 685 } 686 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 proxy_len(proxyobject *pp) 702 { 703 return PyObject_Size(pp->dict); 704 } 705 706 static PyObject * 707 proxy_getitem(proxyobject *pp, PyObject *key) 708 { 709 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 proxy_contains(proxyobject *pp, PyObject *key) 720 { 721 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 proxy_has_key(proxyobject *pp, PyObject *key) 739 { 740 int res = PyDict_Contains(pp->dict, key); 741 if (res < 0) 742 return NULL; 743 return PyBool_FromLong(res); 744 } 745 746 static PyObject * 747 proxy_get(proxyobject *pp, PyObject *args) 748 { 749 PyObject *key, *def = Py_None; 750 751 if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def)) 752 return NULL; 753 return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def); 754 } 755 756 static PyObject * 757 proxy_keys(proxyobject *pp) 758 { 759 return PyMapping_Keys(pp->dict); 760 } 761 762 static PyObject * 763 proxy_values(proxyobject *pp) 764 { 765 return PyMapping_Values(pp->dict); 766 } 767 768 static PyObject * 769 proxy_items(proxyobject *pp) 770 { 771 return PyMapping_Items(pp->dict); 772 } 773 774 static PyObject * 775 proxy_iterkeys(proxyobject *pp) 776 { 777 return PyObject_CallMethod(pp->dict, "iterkeys", NULL); 778 } 779 780 static PyObject * 781 proxy_itervalues(proxyobject *pp) 782 { 783 return PyObject_CallMethod(pp->dict, "itervalues", NULL); 784 } 785 786 static PyObject * 787 proxy_iteritems(proxyobject *pp) 788 { 789 return PyObject_CallMethod(pp->dict, "iteritems", NULL); 790 } 791 static PyObject * 792 proxy_copy(proxyobject *pp) 793 { 794 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 proxy_dealloc(proxyobject *pp) 823 { 824 _PyObject_GC_UNTRACK(pp); 825 Py_DECREF(pp->dict); 826 PyObject_GC_Del(pp); 827 } 828 829 static PyObject * 830 proxy_getiter(proxyobject *pp) 831 { 832 return PyObject_GetIter(pp->dict); 833 } 834 835 static PyObject * 836 proxy_str(proxyobject *pp) 837 { 838 return PyObject_Str(pp->dict); 839 } 840 841 static PyObject * 842 proxy_repr(proxyobject *pp) 843 { 844 PyObject *dictrepr; 845 PyObject *result; 846 847 dictrepr = PyObject_Repr(pp->dict); 848 if (dictrepr == NULL) 849 return NULL; 850 result = PyString_FromFormat("dict_proxy(%s)", PyString_AS_STRING(dictrepr)); 851 Py_DECREF(dictrepr); 852 return result; 853 } 854 855 static int 856 proxy_traverse(PyObject *self, visitproc visit, void *arg) 857 { 858 proxyobject *pp = (proxyobject *)self; 859 Py_VISIT(pp->dict); 860 return 0; 861 } 862 863 static int 864 proxy_compare(proxyobject *v, PyObject *w) 865 { 866 return PyObject_Compare(v->dict, w); 867 } 868 869 static PyObject * 870 proxy_richcompare(proxyobject *v, PyObject *w, int op) 871 { 872 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 PyDictProxy_New(PyObject *dict) 915 { 916 proxyobject *pp; 917 918 pp = PyObject_GC_New(proxyobject, &PyDictProxy_Type); 919 if (pp != NULL) { 920 Py_INCREF(dict); 921 pp->dict = dict; 922 _PyObject_GC_TRACK(pp); 923 } 924 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 wrapper_dealloc(wrapperobject *wp) 941 { 942 PyObject_GC_UnTrack(wp); 943 Py_TRASHCAN_SAFE_BEGIN(wp) 944 Py_XDECREF(wp->descr); 945 Py_XDECREF(wp->self); 946 PyObject_GC_Del(wp); 947 Py_TRASHCAN_SAFE_END(wp) 948 } 949 950 static int 951 wrapper_compare(wrapperobject *a, wrapperobject *b) 952 { 953 if (a->descr == b->descr) 954 return PyObject_Compare(a->self, b->self); 955 else 956 return (a->descr < b->descr) ? -1 : 1; 957 } 958 959 static long 960 wrapper_hash(wrapperobject *wp) 961 { 962 int x, y; 963 x = _Py_HashPointer(wp->descr); 964 if (x == -1) 965 return -1; 966 y = PyObject_Hash(wp->self); 967 if (y == -1) 968 return -1; 969 x = x ^ y; 970 if (x == -1) 971 x = -2; 972 return x; 973 } 974 975 static PyObject * 976 wrapper_repr(wrapperobject *wp) 977 { 978 return PyString_FromFormat("<method-wrapper '%s' of %s object at %p>", 979 wp->descr->d_base->name, 980 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 wrapper_objclass(wrapperobject *wp) 991 { 992 PyObject *c = (PyObject *)wp->descr->d_type; 993 994 Py_INCREF(c); 995 return c; 996 } 997 998 static PyObject * 999 wrapper_name(wrapperobject *wp) 1000 { 1001 char *s = wp->descr->d_base->name; 1002 1003 return PyString_FromString(s); 1004 } 1005 1006 static PyObject * 1007 wrapper_doc(wrapperobject *wp) 1008 { 1009 char *s = wp->descr->d_base->doc; 1010 1011 if (s == NULL) { 1012 Py_INCREF(Py_None); 1013 return Py_None; 1014 } 1015 else { 1016 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 wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds) 1029 { 1030 wrapperfunc wrapper = wp->descr->d_base->wrapper; 1031 PyObject *self = wp->self; 1032 1033 if (wp->descr->d_base->flags & PyWrapperFlag_KEYWORDS) { 1034 wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper; 1035 return (*wk)(self, args, wp->descr->d_wrapped, kwds); 1036 } 1037 1038 if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) { 1039 PyErr_Format(PyExc_TypeError, 1040 "wrapper %s doesn't take keyword arguments", 1041 wp->descr->d_base->name); 1042 return NULL; 1043 } 1044 return (*wrapper)(self, args, wp->descr->d_wrapped); 1045 } 1046 1047 static int 1048 wrapper_traverse(PyObject *self, visitproc visit, void *arg) 1049 { 1050 wrapperobject *wp = (wrapperobject *)self; 1051 Py_VISIT(wp->descr); 1052 Py_VISIT(wp->self); 1053 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 PyWrapper_New(PyObject *d, PyObject *self) 1096 { 1097 wrapperobject *wp; 1098 PyWrapperDescrObject *descr; 1099 1100 assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type)); 1101 descr = (PyWrapperDescrObject *)d; 1102 assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), 1103 (PyObject *)(descr->d_type))); 1104 1105 wp = PyObject_GC_New(wrapperobject, &wrappertype); 1106 if (wp != NULL) { 1107 Py_INCREF(descr); 1108 wp->descr = descr; 1109 Py_INCREF(self); 1110 wp->self = self; 1111 _PyObject_GC_TRACK(wp); 1112 } 1113 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 property_getter(PyObject *self, PyObject *getter) 1175 { 1176 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 property_setter(PyObject *self, PyObject *setter) 1185 { 1186 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 property_deleter(PyObject *self, PyObject *deleter) 1195 { 1196 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 property_dealloc(PyObject *self) 1210 { 1211 propertyobject *gs = (propertyobject *)self; 1212 1213 _PyObject_GC_UNTRACK(self); 1214 Py_XDECREF(gs->prop_get); 1215 Py_XDECREF(gs->prop_set); 1216 Py_XDECREF(gs->prop_del); 1217 Py_XDECREF(gs->prop_doc); 1218 self->ob_type->tp_free(self); 1219 } 1220 1221 static PyObject * 1222 property_descr_get(PyObject *self, PyObject *obj, PyObject *type) 1223 { 1224 propertyobject *gs = (propertyobject *)self; 1225 1226 if (obj == NULL || obj == Py_None) { 1227 Py_INCREF(self); 1228 return self; 1229 } 1230 if (gs->prop_get == NULL) { 1231 PyErr_SetString(PyExc_AttributeError, "unreadable attribute"); 1232 return NULL; 1233 } 1234 return PyObject_CallFunction(gs->prop_get, "(O)", obj); 1235 } 1236 1237 static int 1238 property_descr_set(PyObject *self, PyObject *obj, PyObject *value) 1239 { 1240 propertyobject *gs = (propertyobject *)self; 1241 PyObject *func, *res; 1242 1243 if (value == NULL) 1244 func = gs->prop_del; 1245 else 1246 func = gs->prop_set; 1247 if (func == NULL) { 1248 PyErr_SetString(PyExc_AttributeError, 1249 value == NULL ? 1250 "can't delete attribute" : 1251 "can't set attribute"); 1252 return -1; 1253 } 1254 if (value == NULL) 1255 res = PyObject_CallFunction(func, "(O)", obj); 1256 else 1257 res = PyObject_CallFunction(func, "(OO)", obj, value); 1258 if (res == NULL) 1259 return -1; 1260 Py_DECREF(res); 1261 return 0; 1262 } 1263 1264 static PyObject * 1265 property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *del) 1266 { 1267 propertyobject *pold = (propertyobject *)old; 1268 PyObject *new, *type, *doc; 1269 1270 type = PyObject_Type(old); 1271 if (type == NULL) 1272 return NULL; 1273 1274 if (get == NULL || get == Py_None) { 1275 Py_XDECREF(get); 1276 get = pold->prop_get ? pold->prop_get : Py_None; 1277 } 1278 if (set == NULL || set == Py_None) { 1279 Py_XDECREF(set); 1280 set = pold->prop_set ? pold->prop_set : Py_None; 1281 } 1282 if (del == NULL || del == Py_None) { 1283 Py_XDECREF(del); 1284 del = pold->prop_del ? pold->prop_del : Py_None; 1285 } 1286 if (pold->getter_doc && get != Py_None) { 1287 /* make _init use __doc__ from getter */ 1288 doc = Py_None; 1289 } 1290 else { 1291 doc = pold->prop_doc ? pold->prop_doc : Py_None; 1292 } 1293 1294 new = PyObject_CallFunction(type, "OOOO", get, set, del, doc); 1295 Py_DECREF(type); 1296 if (new == NULL) 1297 return NULL; 1298 return new; 1299 } 1300 1301 static int 1302 property_init(PyObject *self, PyObject *args, PyObject *kwds) 1303 { 1304 PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; 1305 static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; 1306 propertyobject *prop = (propertyobject *)self; 1307 1308 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", 1309 kwlist, &get, &set, &del, &doc)) 1310 return -1; 1311 1312 if (get == Py_None) 1313 get = NULL; 1314 if (set == Py_None) 1315 set = NULL; 1316 if (del == Py_None) 1317 del = NULL; 1318 1319 Py_XINCREF(get); 1320 Py_XINCREF(set); 1321 Py_XINCREF(del); 1322 Py_XINCREF(doc); 1323 1324 prop->prop_get = get; 1325 prop->prop_set = set; 1326 prop->prop_del = del; 1327 prop->prop_doc = doc; 1328 prop->getter_doc = 0; 1329 1330 /* if no docstring given and the getter has one, use that one */ 1331 if ((doc == NULL || doc == Py_None) && get != NULL) { 1332 PyObject *get_doc = PyObject_GetAttrString(get, "__doc__"); 1333 if (get_doc) { 1334 if (Py_TYPE(self) == &PyProperty_Type) { 1335 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 int err = PyObject_SetAttrString(self, "__doc__", get_doc); 1343 Py_DECREF(get_doc); 1344 if (err < 0) 1345 return -1; 1346 } 1347 prop->getter_doc = 1; 1348 } 1349 else if (PyErr_ExceptionMatches(PyExc_Exception)) { 1350 PyErr_Clear(); 1351 } 1352 else { 1353 return -1; 1354 } 1355 } 1356 1357 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 property_traverse(PyObject *self, visitproc visit, void *arg) 1388 { 1389 propertyobject *pp = (propertyobject *)self; 1390 Py_VISIT(pp->prop_get); 1391 Py_VISIT(pp->prop_set); 1392 Py_VISIT(pp->prop_del); 1393 Py_VISIT(pp->prop_doc); 1394 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 }; 1440