Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 /* Descriptors -- a new, flexible way to describe attributes */ | 1 /* Descriptors -- a new, flexible way to describe attributes */ |
2 | 2 |
3 #include "Python.h" | 3 #include "Python.h" |
4 #include "structmember.h" /* Why is this not included in Python.h? */ | 4 #include "structmember.h" /* Why is this not included in Python.h? */ |
5 | 5 |
6 static void | 6 static void |
7 descr_dealloc(PyDescrObject *descr) | 7 descr_dealloc(PyDescrObject *descr) |
8 { | 8 { |
9 _PyObject_GC_UNTRACK(descr); | 9 _PyObject_GC_UNTRACK(descr); |
10 Py_XDECREF(descr->d_type); | 10 Py_XDECREF(descr->d_type); |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
219 argc = PyTuple_GET_SIZE(args); | 219 argc = PyTuple_GET_SIZE(args); |
220 if (argc < 1) { | 220 if (argc < 1) { |
221 PyErr_Format(PyExc_TypeError, | 221 PyErr_Format(PyExc_TypeError, |
222 "descriptor '%V' of '%.100s' " | 222 "descriptor '%V' of '%.100s' " |
223 "object needs an argument", | 223 "object needs an argument", |
224 descr_name((PyDescrObject *)descr), "?", | 224 descr_name((PyDescrObject *)descr), "?", |
225 PyDescr_TYPE(descr)->tp_name); | 225 PyDescr_TYPE(descr)->tp_name); |
226 return NULL; | 226 return NULL; |
227 } | 227 } |
228 self = PyTuple_GET_ITEM(args, 0); | 228 self = PyTuple_GET_ITEM(args, 0); |
229 if (!PyObject_IsInstance(self, (PyObject *)PyDescr_TYPE(descr))) { | 229 if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), |
230 (PyObject *)PyDescr_TYPE(descr))) { | |
230 PyErr_Format(PyExc_TypeError, | 231 PyErr_Format(PyExc_TypeError, |
231 "descriptor '%V' " | 232 "descriptor '%V' " |
232 "requires a '%.100s' object " | 233 "requires a '%.100s' object " |
233 "but received a '%.100s'", | 234 "but received a '%.100s'", |
234 descr_name((PyDescrObject *)descr), "?", | 235 descr_name((PyDescrObject *)descr), "?", |
235 PyDescr_TYPE(descr)->tp_name, | 236 PyDescr_TYPE(descr)->tp_name, |
236 self->ob_type->tp_name); | 237 self->ob_type->tp_name); |
237 return NULL; | 238 return NULL; |
238 } | 239 } |
239 | 240 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
277 argc = PyTuple_GET_SIZE(args); | 278 argc = PyTuple_GET_SIZE(args); |
278 if (argc < 1) { | 279 if (argc < 1) { |
279 PyErr_Format(PyExc_TypeError, | 280 PyErr_Format(PyExc_TypeError, |
280 "descriptor '%V' of '%.100s' " | 281 "descriptor '%V' of '%.100s' " |
281 "object needs an argument", | 282 "object needs an argument", |
282 descr_name((PyDescrObject *)descr), "?", | 283 descr_name((PyDescrObject *)descr), "?", |
283 PyDescr_TYPE(descr)->tp_name); | 284 PyDescr_TYPE(descr)->tp_name); |
284 return NULL; | 285 return NULL; |
285 } | 286 } |
286 self = PyTuple_GET_ITEM(args, 0); | 287 self = PyTuple_GET_ITEM(args, 0); |
287 if (!PyObject_IsInstance(self, (PyObject *)PyDescr_TYPE(descr))) { | 288 if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), |
289 (PyObject *)PyDescr_TYPE(descr))) { | |
288 PyErr_Format(PyExc_TypeError, | 290 PyErr_Format(PyExc_TypeError, |
289 "descriptor '%V' " | 291 "descriptor '%V' " |
290 "requires a '%.100s' object " | 292 "requires a '%.100s' object " |
291 "but received a '%.100s'", | 293 "but received a '%.100s'", |
292 descr_name((PyDescrObject *)descr), "?", | 294 descr_name((PyDescrObject *)descr), "?", |
293 PyDescr_TYPE(descr)->tp_name, | 295 PyDescr_TYPE(descr)->tp_name, |
294 self->ob_type->tp_name); | 296 self->ob_type->tp_name); |
295 return NULL; | 297 return NULL; |
296 } | 298 } |
297 | 299 |
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
694 0, /* sq_ass_slice */ | 696 0, /* sq_ass_slice */ |
695 (objobjproc)proxy_contains, /* sq_contains */ | 697 (objobjproc)proxy_contains, /* sq_contains */ |
696 0, /* sq_inplace_concat */ | 698 0, /* sq_inplace_concat */ |
697 0, /* sq_inplace_repeat */ | 699 0, /* sq_inplace_repeat */ |
698 }; | 700 }; |
699 | 701 |
700 static PyObject * | 702 static PyObject * |
701 proxy_get(proxyobject *pp, PyObject *args) | 703 proxy_get(proxyobject *pp, PyObject *args) |
702 { | 704 { |
703 PyObject *key, *def = Py_None; | 705 PyObject *key, *def = Py_None; |
706 _Py_IDENTIFIER(get); | |
704 | 707 |
705 if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def)) | 708 if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def)) |
706 return NULL; | 709 return NULL; |
707 return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def); | 710 return _PyObject_CallMethodId(pp->dict, &PyId_get, "(OO)", key, def); |
708 } | 711 } |
709 | 712 |
710 static PyObject * | 713 static PyObject * |
711 proxy_keys(proxyobject *pp) | 714 proxy_keys(proxyobject *pp) |
712 { | 715 { |
713 return PyObject_CallMethod(pp->dict, "keys", NULL); | 716 _Py_IDENTIFIER(keys); |
717 return _PyObject_CallMethodId(pp->dict, &PyId_keys, NULL); | |
714 } | 718 } |
715 | 719 |
716 static PyObject * | 720 static PyObject * |
717 proxy_values(proxyobject *pp) | 721 proxy_values(proxyobject *pp) |
718 { | 722 { |
719 return PyObject_CallMethod(pp->dict, "values", NULL); | 723 _Py_IDENTIFIER(values); |
724 return _PyObject_CallMethodId(pp->dict, &PyId_values, NULL); | |
720 } | 725 } |
721 | 726 |
722 static PyObject * | 727 static PyObject * |
723 proxy_items(proxyobject *pp) | 728 proxy_items(proxyobject *pp) |
724 { | 729 { |
725 return PyObject_CallMethod(pp->dict, "items", NULL); | 730 _Py_IDENTIFIER(items); |
731 return _PyObject_CallMethodId(pp->dict, &PyId_items, NULL); | |
726 } | 732 } |
727 | 733 |
728 static PyObject * | 734 static PyObject * |
729 proxy_copy(proxyobject *pp) | 735 proxy_copy(proxyobject *pp) |
730 { | 736 { |
731 return PyObject_CallMethod(pp->dict, "copy", NULL); | 737 _Py_IDENTIFIER(copy); |
738 return _PyObject_CallMethodId(pp->dict, &PyId_copy, NULL); | |
732 } | 739 } |
733 | 740 |
734 static PyMethodDef proxy_methods[] = { | 741 static PyMethodDef proxy_methods[] = { |
735 {"get", (PyCFunction)proxy_get, METH_VARARGS, | 742 {"get", (PyCFunction)proxy_get, METH_VARARGS, |
736 PyDoc_STR("D.get(k[,d]) -> D[k] if k in D, else d." | 743 PyDoc_STR("D.get(k[,d]) -> D[k] if k in D, else d." |
737 " d defaults to None.")}, | 744 " d defaults to None.")}, |
738 {"keys", (PyCFunction)proxy_keys, METH_NOARGS, | 745 {"keys", (PyCFunction)proxy_keys, METH_NOARGS, |
739 PyDoc_STR("D.keys() -> list of D's keys")}, | 746 PyDoc_STR("D.keys() -> list of D's keys")}, |
740 {"values", (PyCFunction)proxy_values, METH_NOARGS, | 747 {"values", (PyCFunction)proxy_values, METH_NOARGS, |
741 PyDoc_STR("D.values() -> list of D's values")}, | 748 PyDoc_STR("D.values() -> list of D's values")}, |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
837 } | 844 } |
838 return (PyObject *)pp; | 845 return (PyObject *)pp; |
839 } | 846 } |
840 | 847 |
841 | 848 |
842 /* --- Wrapper object for "slot" methods --- */ | 849 /* --- Wrapper object for "slot" methods --- */ |
843 | 850 |
844 /* This has no reason to be in this file except that adding new files is a | 851 /* This has no reason to be in this file except that adding new files is a |
845 bit of a pain */ | 852 bit of a pain */ |
846 | 853 |
847 /* forward */ | |
848 static PyTypeObject wrappertype; | |
849 | |
850 typedef struct { | 854 typedef struct { |
851 PyObject_HEAD | 855 PyObject_HEAD |
852 PyWrapperDescrObject *descr; | 856 PyWrapperDescrObject *descr; |
853 PyObject *self; | 857 PyObject *self; |
854 } wrapperobject; | 858 } wrapperobject; |
855 | 859 |
856 #define Wrapper_Check(v) (Py_TYPE(v) == &wrappertype) | 860 #define Wrapper_Check(v) (Py_TYPE(v) == &_PyMethodWrapper_Type) |
857 | 861 |
858 static void | 862 static void |
859 wrapper_dealloc(wrapperobject *wp) | 863 wrapper_dealloc(wrapperobject *wp) |
860 { | 864 { |
861 PyObject_GC_UnTrack(wp); | 865 PyObject_GC_UnTrack(wp); |
862 Py_TRASHCAN_SAFE_BEGIN(wp) | 866 Py_TRASHCAN_SAFE_BEGIN(wp) |
863 Py_XDECREF(wp->descr); | 867 Py_XDECREF(wp->descr); |
864 Py_XDECREF(wp->self); | 868 Py_XDECREF(wp->self); |
865 PyObject_GC_Del(wp); | 869 PyObject_GC_Del(wp); |
866 Py_TRASHCAN_SAFE_END(wp) | 870 Py_TRASHCAN_SAFE_END(wp) |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1012 | 1016 |
1013 static int | 1017 static int |
1014 wrapper_traverse(PyObject *self, visitproc visit, void *arg) | 1018 wrapper_traverse(PyObject *self, visitproc visit, void *arg) |
1015 { | 1019 { |
1016 wrapperobject *wp = (wrapperobject *)self; | 1020 wrapperobject *wp = (wrapperobject *)self; |
1017 Py_VISIT(wp->descr); | 1021 Py_VISIT(wp->descr); |
1018 Py_VISIT(wp->self); | 1022 Py_VISIT(wp->self); |
1019 return 0; | 1023 return 0; |
1020 } | 1024 } |
1021 | 1025 |
1022 static PyTypeObject wrappertype = { | 1026 PyTypeObject _PyMethodWrapper_Type = { |
1023 PyVarObject_HEAD_INIT(&PyType_Type, 0) | 1027 PyVarObject_HEAD_INIT(&PyType_Type, 0) |
1024 "method-wrapper", /* tp_name */ | 1028 "method-wrapper", /* tp_name */ |
1025 sizeof(wrapperobject), /* tp_basicsize */ | 1029 sizeof(wrapperobject), /* tp_basicsize */ |
1026 0, /* tp_itemsize */ | 1030 0, /* tp_itemsize */ |
1027 /* methods */ | 1031 /* methods */ |
1028 (destructor)wrapper_dealloc, /* tp_dealloc */ | 1032 (destructor)wrapper_dealloc, /* tp_dealloc */ |
1029 0, /* tp_print */ | 1033 0, /* tp_print */ |
1030 0, /* tp_getattr */ | 1034 0, /* tp_getattr */ |
1031 0, /* tp_setattr */ | 1035 0, /* tp_setattr */ |
1032 0, /* tp_reserved */ | 1036 0, /* tp_reserved */ |
(...skipping 25 matching lines...) Expand all Loading... | |
1058 }; | 1062 }; |
1059 | 1063 |
1060 PyObject * | 1064 PyObject * |
1061 PyWrapper_New(PyObject *d, PyObject *self) | 1065 PyWrapper_New(PyObject *d, PyObject *self) |
1062 { | 1066 { |
1063 wrapperobject *wp; | 1067 wrapperobject *wp; |
1064 PyWrapperDescrObject *descr; | 1068 PyWrapperDescrObject *descr; |
1065 | 1069 |
1066 assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type)); | 1070 assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type)); |
1067 descr = (PyWrapperDescrObject *)d; | 1071 descr = (PyWrapperDescrObject *)d; |
1068 assert(PyObject_IsInstance(self, (PyObject *)PyDescr_TYPE(descr))); | 1072 assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), |
1069 | 1073 (PyObject *)PyDescr_TYPE(descr))); |
1070 wp = PyObject_GC_New(wrapperobject, &wrappertype); | 1074 |
1075 wp = PyObject_GC_New(wrapperobject, &_PyMethodWrapper_Type); | |
1071 if (wp != NULL) { | 1076 if (wp != NULL) { |
1072 Py_INCREF(descr); | 1077 Py_INCREF(descr); |
1073 wp->descr = descr; | 1078 wp->descr = descr; |
1074 Py_INCREF(self); | 1079 Py_INCREF(self); |
1075 wp->self = self; | 1080 wp->self = self; |
1076 _PyObject_GC_TRACK(wp); | 1081 _PyObject_GC_TRACK(wp); |
1077 } | 1082 } |
1078 return (PyObject *)wp; | 1083 return (PyObject *)wp; |
1079 } | 1084 } |
1080 | 1085 |
1081 | 1086 |
1082 /* A built-in 'property' type */ | 1087 /* A built-in 'property' type */ |
1083 | 1088 |
1084 /* | 1089 /* |
1085 class property(object): | 1090 class property(object): |
1086 | 1091 |
1087 def __init__(self, fget=None, fset=None, fdel=None, doc=None): | 1092 def __init__(self, fget=None, fset=None, fdel=None, doc=None): |
1088 if doc is None and fget is not None and hasattr(fget, "__doc__"): | 1093 if doc is None and fget is not None and hasattr(fget, "__doc__"): |
1089 doc = fget.__doc__ | 1094 doc = fget.__doc__ |
1090 self.__get = fget | 1095 self.__get = fget |
1091 self.__set = fset | 1096 self.__set = fset |
1092 self.__del = fdel | 1097 self.__del = fdel |
1093 self.__doc__ = doc | 1098 self.__doc__ = doc |
1094 for f in (fget, fset, fdel): | |
1095 if getattr(f, '__isabstractmethod__', False): | |
1096 self.__isabstractmethod__ = True | |
1097 break | |
1098 | 1099 |
1099 def __get__(self, inst, type=None): | 1100 def __get__(self, inst, type=None): |
1100 if inst is None: | 1101 if inst is None: |
1101 return self | 1102 return self |
1102 if self.__get is None: | 1103 if self.__get is None: |
1103 raise AttributeError, "unreadable attribute" | 1104 raise AttributeError, "unreadable attribute" |
1104 return self.__get(inst) | 1105 return self.__get(inst) |
1105 | 1106 |
1106 def __set__(self, inst, value): | 1107 def __set__(self, inst, value): |
1107 if self.__set is None: | 1108 if self.__set is None: |
1108 raise AttributeError, "can't set attribute" | 1109 raise AttributeError, "can't set attribute" |
1109 return self.__set(inst, value) | 1110 return self.__set(inst, value) |
1110 | 1111 |
1111 def __delete__(self, inst): | 1112 def __delete__(self, inst): |
1112 if self.__del is None: | 1113 if self.__del is None: |
1113 raise AttributeError, "can't delete attribute" | 1114 raise AttributeError, "can't delete attribute" |
1114 return self.__del(inst) | 1115 return self.__del(inst) |
1115 | 1116 |
1116 */ | 1117 */ |
1117 | 1118 |
1118 typedef struct { | 1119 typedef struct { |
1119 PyObject_HEAD | 1120 PyObject_HEAD |
1120 PyObject *prop_get; | 1121 PyObject *prop_get; |
1121 PyObject *prop_set; | 1122 PyObject *prop_set; |
1122 PyObject *prop_del; | 1123 PyObject *prop_del; |
1123 PyObject *prop_doc; | 1124 PyObject *prop_doc; |
1124 PyObject *prop_isabstract; | |
durban
2011/03/19 21:36:09
An int flag probably would be enough (like getter_
| |
1125 int getter_doc; | 1125 int getter_doc; |
1126 } propertyobject; | 1126 } propertyobject; |
1127 | 1127 |
1128 static PyObject * property_copy(PyObject *, PyObject *, PyObject *, | 1128 static PyObject * property_copy(PyObject *, PyObject *, PyObject *, |
1129 PyObject *); | 1129 PyObject *); |
1130 | 1130 |
1131 static PyMemberDef property_members[] = { | 1131 static PyMemberDef property_members[] = { |
1132 {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY}, | 1132 {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY}, |
1133 {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY}, | 1133 {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY}, |
1134 {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY}, | 1134 {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY}, |
1135 {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY}, | 1135 {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY}, |
1136 {"__isabstractmethod__", T_OBJECT, | |
1137 offsetof(propertyobject, prop_isabstract), READONLY}, | |
1138 {0} | 1136 {0} |
1139 }; | 1137 }; |
1140 | 1138 |
1141 | 1139 |
1142 PyDoc_STRVAR(getter_doc, | 1140 PyDoc_STRVAR(getter_doc, |
1143 "Descriptor to change the getter on a property."); | 1141 "Descriptor to change the getter on a property."); |
1144 | 1142 |
1145 static PyObject * | 1143 static PyObject * |
1146 property_getter(PyObject *self, PyObject *getter) | 1144 property_getter(PyObject *self, PyObject *getter) |
1147 { | 1145 { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1180 static void | 1178 static void |
1181 property_dealloc(PyObject *self) | 1179 property_dealloc(PyObject *self) |
1182 { | 1180 { |
1183 propertyobject *gs = (propertyobject *)self; | 1181 propertyobject *gs = (propertyobject *)self; |
1184 | 1182 |
1185 _PyObject_GC_UNTRACK(self); | 1183 _PyObject_GC_UNTRACK(self); |
1186 Py_XDECREF(gs->prop_get); | 1184 Py_XDECREF(gs->prop_get); |
1187 Py_XDECREF(gs->prop_set); | 1185 Py_XDECREF(gs->prop_set); |
1188 Py_XDECREF(gs->prop_del); | 1186 Py_XDECREF(gs->prop_del); |
1189 Py_XDECREF(gs->prop_doc); | 1187 Py_XDECREF(gs->prop_doc); |
1190 Py_XDECREF(gs->prop_isabstract); | |
1191 self->ob_type->tp_free(self); | 1188 self->ob_type->tp_free(self); |
1192 } | 1189 } |
1193 | 1190 |
1194 static PyObject * | 1191 static PyObject * |
1195 property_descr_get(PyObject *self, PyObject *obj, PyObject *type) | 1192 property_descr_get(PyObject *self, PyObject *obj, PyObject *type) |
1196 { | 1193 { |
1197 propertyobject *gs = (propertyobject *)self; | 1194 propertyobject *gs = (propertyobject *)self; |
1198 | 1195 |
1199 if (obj == NULL || obj == Py_None) { | 1196 if (obj == NULL || obj == Py_None) { |
1200 Py_INCREF(self); | 1197 Py_INCREF(self); |
(...skipping 13 matching lines...) Expand all Loading... | |
1214 PyObject *func, *res; | 1211 PyObject *func, *res; |
1215 | 1212 |
1216 if (value == NULL) | 1213 if (value == NULL) |
1217 func = gs->prop_del; | 1214 func = gs->prop_del; |
1218 else | 1215 else |
1219 func = gs->prop_set; | 1216 func = gs->prop_set; |
1220 if (func == NULL) { | 1217 if (func == NULL) { |
1221 PyErr_SetString(PyExc_AttributeError, | 1218 PyErr_SetString(PyExc_AttributeError, |
1222 value == NULL ? | 1219 value == NULL ? |
1223 "can't delete attribute" : | 1220 "can't delete attribute" : |
1224 "can't set attribute"); | 1221 "can't set attribute"); |
1225 return -1; | 1222 return -1; |
1226 } | 1223 } |
1227 if (value == NULL) | 1224 if (value == NULL) |
1228 res = PyObject_CallFunctionObjArgs(func, obj, NULL); | 1225 res = PyObject_CallFunctionObjArgs(func, obj, NULL); |
1229 else | 1226 else |
1230 res = PyObject_CallFunctionObjArgs(func, obj, value, NULL); | 1227 res = PyObject_CallFunctionObjArgs(func, obj, value, NULL); |
1231 if (res == NULL) | 1228 if (res == NULL) |
1232 return -1; | 1229 return -1; |
1233 Py_DECREF(res); | 1230 Py_DECREF(res); |
1234 return 0; | 1231 return 0; |
(...skipping 29 matching lines...) Expand all Loading... | |
1264 doc = pold->prop_doc ? pold->prop_doc : Py_None; | 1261 doc = pold->prop_doc ? pold->prop_doc : Py_None; |
1265 } | 1262 } |
1266 | 1263 |
1267 new = PyObject_CallFunction(type, "OOOO", get, set, del, doc); | 1264 new = PyObject_CallFunction(type, "OOOO", get, set, del, doc); |
1268 Py_DECREF(type); | 1265 Py_DECREF(type); |
1269 if (new == NULL) | 1266 if (new == NULL) |
1270 return NULL; | 1267 return NULL; |
1271 return new; | 1268 return new; |
1272 } | 1269 } |
1273 | 1270 |
1274 static void | |
1275 property_identify_abstract_method(PyObject *self, PyObject *method) | |
1276 { | |
1277 /* Set self.__isabstractmethod__ if method is abstract */ | |
1278 if (method != NULL){ | |
1279 PyObject *is_abstract = PyObject_GetAttrString(method, | |
durban
2011/03/19 21:36:09
NULL/exception check?
dsdale24
2011/03/19 22:13:42
This is the part where I am weak. Can you point me
| |
1280 "__isabstractmethod__"); | |
1281 if (PyObject_IsTrue(is_abstract) > 0){ | |
1282 Py_INCREF(Py_True); | |
1283 PyObject_SetAttrString(self, "__isabstractmethod__", Py_True); | |
durban
2011/03/19 21:36:10
(You could directly assign to the prop_isabstract
dsdale24
2011/03/19 22:13:42
I got compilation errors when I tried.
| |
1284 } | |
1285 Py_DECREF(is_abstract); | |
durban
2011/03/19 21:36:10
Can be NULL.
| |
1286 } | |
1287 } | |
1288 | |
1289 static int | 1271 static int |
1290 property_init(PyObject *self, PyObject *args, PyObject *kwds) | 1272 property_init(PyObject *self, PyObject *args, PyObject *kwds) |
1291 { | 1273 { |
1292 PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; | 1274 PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; |
1293 static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; | 1275 static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; |
1294 propertyobject *prop = (propertyobject *)self; | 1276 propertyobject *prop = (propertyobject *)self; |
1295 | 1277 |
1296 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", | 1278 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", |
1297 kwlist, &get, &set, &del, &doc)) | 1279 kwlist, &get, &set, &del, &doc)) |
1298 return -1; | 1280 return -1; |
1299 | 1281 |
1300 if (get == Py_None) | 1282 if (get == Py_None) |
1301 get = NULL; | 1283 get = NULL; |
1302 if (set == Py_None) | 1284 if (set == Py_None) |
1303 set = NULL; | 1285 set = NULL; |
1304 if (del == Py_None) | 1286 if (del == Py_None) |
1305 del = NULL; | 1287 del = NULL; |
1306 | 1288 |
1307 Py_XINCREF(get); | 1289 Py_XINCREF(get); |
1308 Py_XINCREF(set); | 1290 Py_XINCREF(set); |
1309 Py_XINCREF(del); | 1291 Py_XINCREF(del); |
1310 Py_XINCREF(doc); | 1292 Py_XINCREF(doc); |
1311 Py_INCREF(Py_False); | |
1312 | 1293 |
1313 prop->prop_get = get; | 1294 prop->prop_get = get; |
1314 prop->prop_set = set; | 1295 prop->prop_set = set; |
1315 prop->prop_del = del; | 1296 prop->prop_del = del; |
1316 prop->prop_doc = doc; | 1297 prop->prop_doc = doc; |
1317 prop->prop_isabstract = Py_False; | |
1318 prop->getter_doc = 0; | 1298 prop->getter_doc = 0; |
1319 | 1299 |
1320 /* if no docstring given and the getter has one, use that one */ | 1300 /* if no docstring given and the getter has one, use that one */ |
1321 if ((doc == NULL || doc == Py_None) && get != NULL) { | 1301 if ((doc == NULL || doc == Py_None) && get != NULL) { |
1322 PyObject *get_doc = PyObject_GetAttrString(get, "__doc__"); | 1302 _Py_IDENTIFIER(__doc__); |
1303 PyObject *get_doc = _PyObject_GetAttrId(get, &PyId___doc__); | |
1323 if (get_doc) { | 1304 if (get_doc) { |
1324 if (Py_TYPE(self) == &PyProperty_Type) { | 1305 if (Py_TYPE(self) == &PyProperty_Type) { |
1325 Py_XDECREF(prop->prop_doc); | 1306 Py_XDECREF(prop->prop_doc); |
1326 prop->prop_doc = get_doc; | 1307 prop->prop_doc = get_doc; |
1327 } | 1308 } |
1328 else { | 1309 else { |
1329 /* If this is a property subclass, put __doc__ | 1310 /* If this is a property subclass, put __doc__ |
1330 in dict of the subclass instance instead, | 1311 in dict of the subclass instance instead, |
1331 otherwise it gets shadowed by __doc__ in the | 1312 otherwise it gets shadowed by __doc__ in the |
1332 class's dict. */ | 1313 class's dict. */ |
1333 int err = PyObject_SetAttrString(self, "__doc__", get_doc); | 1314 int err = _PyObject_SetAttrId(self, &PyId___doc__, get_doc); |
1334 Py_DECREF(get_doc); | 1315 Py_DECREF(get_doc); |
1335 if (err < 0) | 1316 if (err < 0) |
1336 return -1; | 1317 return -1; |
1337 } | 1318 } |
1338 prop->getter_doc = 1; | 1319 prop->getter_doc = 1; |
1339 } | 1320 } |
1340 else if (PyErr_ExceptionMatches(PyExc_Exception)) { | 1321 else if (PyErr_ExceptionMatches(PyExc_Exception)) { |
1341 PyErr_Clear(); | 1322 PyErr_Clear(); |
1342 } | 1323 } |
1343 else { | 1324 else { |
1344 return -1; | 1325 return -1; |
1345 } | 1326 } |
1346 } | 1327 } |
1347 | 1328 |
1348 /* set __isabstractmethod__ if fget, fset, or fdel are abstract methods */ | |
durban
2011/03/19 21:36:10
This doesn't handle the case if the fget/fset/fdel
dsdale24
2011/03/19 22:13:42
Would that ever happen? I think the only way to ch
| |
1349 property_identify_abstract_method(self, get); | |
1350 property_identify_abstract_method(self, set); | |
1351 property_identify_abstract_method(self, del); | |
1352 | |
1353 return 0; | 1329 return 0; |
1354 } | 1330 } |
1331 | |
1332 static PyObject * | |
1333 property_get___isabstractmethod__(propertyobject *prop, void *closure) | |
1334 { | |
1335 int res = _PyObject_IsAbstract(prop->prop_get); | |
1336 if (res == -1) { | |
1337 return NULL; | |
1338 } | |
1339 else if (res) { | |
1340 Py_RETURN_TRUE; | |
1341 } | |
1342 | |
1343 res = _PyObject_IsAbstract(prop->prop_set); | |
1344 if (res == -1) { | |
1345 return NULL; | |
1346 } | |
1347 else if (res) { | |
1348 Py_RETURN_TRUE; | |
1349 } | |
1350 | |
1351 res = _PyObject_IsAbstract(prop->prop_del); | |
1352 if (res == -1) { | |
1353 return NULL; | |
1354 } | |
1355 else if (res) { | |
1356 Py_RETURN_TRUE; | |
1357 } | |
1358 Py_RETURN_FALSE; | |
1359 } | |
1360 | |
1361 static PyGetSetDef property_getsetlist[] = { | |
1362 {"__isabstractmethod__", | |
1363 (getter)property_get___isabstractmethod__, NULL, | |
1364 NULL, | |
1365 NULL}, | |
1366 {NULL} /* Sentinel */ | |
1367 }; | |
1355 | 1368 |
1356 PyDoc_STRVAR(property_doc, | 1369 PyDoc_STRVAR(property_doc, |
1357 "property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n" | 1370 "property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n" |
1358 "\n" | 1371 "\n" |
1359 "fget is a function to be used for getting an attribute value, and likewise\n" | 1372 "fget is a function to be used for getting an attribute value, and likewise\n" |
1360 "fset is a function for setting, and fdel a function for del'ing, an\n" | 1373 "fset is a function for setting, and fdel a function for del'ing, an\n" |
1361 "attribute. Typical use is to define a managed attribute x:\n" | 1374 "attribute. Typical use is to define a managed attribute x:\n" |
1362 "class C(object):\n" | 1375 "class C(object):\n" |
1363 " def getx(self): return self._x\n" | 1376 " def getx(self): return self._x\n" |
1364 " def setx(self, value): self._x = value\n" | 1377 " def setx(self, value): self._x = value\n" |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1411 Py_TPFLAGS_BASETYPE, /* tp_flags */ | 1424 Py_TPFLAGS_BASETYPE, /* tp_flags */ |
1412 property_doc, /* tp_doc */ | 1425 property_doc, /* tp_doc */ |
1413 property_traverse, /* tp_traverse */ | 1426 property_traverse, /* tp_traverse */ |
1414 0, /* tp_clear */ | 1427 0, /* tp_clear */ |
1415 0, /* tp_richcompare */ | 1428 0, /* tp_richcompare */ |
1416 0, /* tp_weaklistoffset */ | 1429 0, /* tp_weaklistoffset */ |
1417 0, /* tp_iter */ | 1430 0, /* tp_iter */ |
1418 0, /* tp_iternext */ | 1431 0, /* tp_iternext */ |
1419 property_methods, /* tp_methods */ | 1432 property_methods, /* tp_methods */ |
1420 property_members, /* tp_members */ | 1433 property_members, /* tp_members */ |
1421 0, /* tp_getset */ | 1434 property_getsetlist, /* tp_getset */ |
1422 0, /* tp_base */ | 1435 0, /* tp_base */ |
1423 0, /* tp_dict */ | 1436 0, /* tp_dict */ |
1424 property_descr_get, /* tp_descr_get */ | 1437 property_descr_get, /* tp_descr_get */ |
1425 property_descr_set, /* tp_descr_set */ | 1438 property_descr_set, /* tp_descr_set */ |
1426 0, /* tp_dictoffset */ | 1439 0, /* tp_dictoffset */ |
1427 property_init, /* tp_init */ | 1440 property_init, /* tp_init */ |
1428 PyType_GenericAlloc, /* tp_alloc */ | 1441 PyType_GenericAlloc, /* tp_alloc */ |
1429 PyType_GenericNew, /* tp_new */ | 1442 PyType_GenericNew, /* tp_new */ |
1430 PyObject_GC_Del, /* tp_free */ | 1443 PyObject_GC_Del, /* tp_free */ |
1431 }; | 1444 }; |
LEFT | RIGHT |