Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(164949)

Side by Side Diff: Objects/descrobject.c

Issue 11610: Improving property to accept abstract methods
Patch Set: Created 8 years, 8 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« Lib/test/test_abc.py ('K') | « Lib/test/test_abc.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 1073 matching lines...) Expand 10 before | Expand all | Expand 10 after
1084 /* 1084 /*
1085 class property(object): 1085 class property(object):
1086 1086
1087 def __init__(self, fget=None, fset=None, fdel=None, doc=None): 1087 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__"): 1088 if doc is None and fget is not None and hasattr(fget, "__doc__"):
1089 doc = fget.__doc__ 1089 doc = fget.__doc__
1090 self.__get = fget 1090 self.__get = fget
1091 self.__set = fset 1091 self.__set = fset
1092 self.__del = fdel 1092 self.__del = fdel
1093 self.__doc__ = doc 1093 self.__doc__ = doc
1094 for f in (fget, fset, fdel):
1095 if getattr(f, '__isabstractmethod__', False):
1096 self.__isabstractmethod__ = True
1097 break
1094 1098
1095 def __get__(self, inst, type=None): 1099 def __get__(self, inst, type=None):
1096 if inst is None: 1100 if inst is None:
1097 return self 1101 return self
1098 if self.__get is None: 1102 if self.__get is None:
1099 raise AttributeError, "unreadable attribute" 1103 raise AttributeError, "unreadable attribute"
1100 return self.__get(inst) 1104 return self.__get(inst)
1101 1105
1102 def __set__(self, inst, value): 1106 def __set__(self, inst, value):
1103 if self.__set is None: 1107 if self.__set is None:
1104 raise AttributeError, "can't set attribute" 1108 raise AttributeError, "can't set attribute"
1105 return self.__set(inst, value) 1109 return self.__set(inst, value)
1106 1110
1107 def __delete__(self, inst): 1111 def __delete__(self, inst):
1108 if self.__del is None: 1112 if self.__del is None:
1109 raise AttributeError, "can't delete attribute" 1113 raise AttributeError, "can't delete attribute"
1110 return self.__del(inst) 1114 return self.__del(inst)
1111 1115
1112 */ 1116 */
1113 1117
1114 typedef struct { 1118 typedef struct {
1115 PyObject_HEAD 1119 PyObject_HEAD
1116 PyObject *prop_get; 1120 PyObject *prop_get;
1117 PyObject *prop_set; 1121 PyObject *prop_set;
1118 PyObject *prop_del; 1122 PyObject *prop_del;
1119 PyObject *prop_doc; 1123 PyObject *prop_doc;
1124 PyObject *prop_isabstract;
durban 2011/03/19 21:36:09 An int flag probably would be enough (like getter_
1120 int getter_doc; 1125 int getter_doc;
1121 } propertyobject; 1126 } propertyobject;
1122 1127
1123 static PyObject * property_copy(PyObject *, PyObject *, PyObject *, 1128 static PyObject * property_copy(PyObject *, PyObject *, PyObject *,
1124 PyObject *); 1129 PyObject *);
1125 1130
1126 static PyMemberDef property_members[] = { 1131 static PyMemberDef property_members[] = {
1127 {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY}, 1132 {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY},
1128 {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY}, 1133 {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY},
1129 {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY}, 1134 {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY},
1130 {"__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},
1131 {0} 1138 {0}
1132 }; 1139 };
1133 1140
1134 1141
1135 PyDoc_STRVAR(getter_doc, 1142 PyDoc_STRVAR(getter_doc,
1136 "Descriptor to change the getter on a property."); 1143 "Descriptor to change the getter on a property.");
1137 1144
1138 static PyObject * 1145 static PyObject *
1139 property_getter(PyObject *self, PyObject *getter) 1146 property_getter(PyObject *self, PyObject *getter)
1140 { 1147 {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1173 static void 1180 static void
1174 property_dealloc(PyObject *self) 1181 property_dealloc(PyObject *self)
1175 { 1182 {
1176 propertyobject *gs = (propertyobject *)self; 1183 propertyobject *gs = (propertyobject *)self;
1177 1184
1178 _PyObject_GC_UNTRACK(self); 1185 _PyObject_GC_UNTRACK(self);
1179 Py_XDECREF(gs->prop_get); 1186 Py_XDECREF(gs->prop_get);
1180 Py_XDECREF(gs->prop_set); 1187 Py_XDECREF(gs->prop_set);
1181 Py_XDECREF(gs->prop_del); 1188 Py_XDECREF(gs->prop_del);
1182 Py_XDECREF(gs->prop_doc); 1189 Py_XDECREF(gs->prop_doc);
1190 Py_XDECREF(gs->prop_isabstract);
1183 self->ob_type->tp_free(self); 1191 self->ob_type->tp_free(self);
1184 } 1192 }
1185 1193
1186 static PyObject * 1194 static PyObject *
1187 property_descr_get(PyObject *self, PyObject *obj, PyObject *type) 1195 property_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1188 { 1196 {
1189 propertyobject *gs = (propertyobject *)self; 1197 propertyobject *gs = (propertyobject *)self;
1190 1198
1191 if (obj == NULL || obj == Py_None) { 1199 if (obj == NULL || obj == Py_None) {
1192 Py_INCREF(self); 1200 Py_INCREF(self);
(...skipping 13 matching lines...) Expand all
1206 PyObject *func, *res; 1214 PyObject *func, *res;
1207 1215
1208 if (value == NULL) 1216 if (value == NULL)
1209 func = gs->prop_del; 1217 func = gs->prop_del;
1210 else 1218 else
1211 func = gs->prop_set; 1219 func = gs->prop_set;
1212 if (func == NULL) { 1220 if (func == NULL) {
1213 PyErr_SetString(PyExc_AttributeError, 1221 PyErr_SetString(PyExc_AttributeError,
1214 value == NULL ? 1222 value == NULL ?
1215 "can't delete attribute" : 1223 "can't delete attribute" :
1216 "can't set attribute"); 1224 "can't set attribute");
1217 return -1; 1225 return -1;
1218 } 1226 }
1219 if (value == NULL) 1227 if (value == NULL)
1220 res = PyObject_CallFunctionObjArgs(func, obj, NULL); 1228 res = PyObject_CallFunctionObjArgs(func, obj, NULL);
1221 else 1229 else
1222 res = PyObject_CallFunctionObjArgs(func, obj, value, NULL); 1230 res = PyObject_CallFunctionObjArgs(func, obj, value, NULL);
1223 if (res == NULL) 1231 if (res == NULL)
1224 return -1; 1232 return -1;
1225 Py_DECREF(res); 1233 Py_DECREF(res);
1226 return 0; 1234 return 0;
(...skipping 27 matching lines...) Expand all
1254 } 1262 }
1255 else { 1263 else {
1256 doc = pold->prop_doc ? pold->prop_doc : Py_None; 1264 doc = pold->prop_doc ? pold->prop_doc : Py_None;
1257 } 1265 }
1258 1266
1259 new = PyObject_CallFunction(type, "OOOO", get, set, del, doc); 1267 new = PyObject_CallFunction(type, "OOOO", get, set, del, doc);
1260 Py_DECREF(type); 1268 Py_DECREF(type);
1261 if (new == NULL) 1269 if (new == NULL)
1262 return NULL; 1270 return NULL;
1263 return new; 1271 return new;
1272 }
1273
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 }
1264 } 1287 }
1265 1288
1266 static int 1289 static int
1267 property_init(PyObject *self, PyObject *args, PyObject *kwds) 1290 property_init(PyObject *self, PyObject *args, PyObject *kwds)
1268 { 1291 {
1269 PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; 1292 PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL;
1270 static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; 1293 static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0};
1271 propertyobject *prop = (propertyobject *)self; 1294 propertyobject *prop = (propertyobject *)self;
1272 1295
1273 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", 1296 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property",
1274 kwlist, &get, &set, &del, &doc)) 1297 kwlist, &get, &set, &del, &doc))
1275 return -1; 1298 return -1;
1276 1299
1277 if (get == Py_None) 1300 if (get == Py_None)
1278 get = NULL; 1301 get = NULL;
1279 if (set == Py_None) 1302 if (set == Py_None)
1280 set = NULL; 1303 set = NULL;
1281 if (del == Py_None) 1304 if (del == Py_None)
1282 del = NULL; 1305 del = NULL;
1283 1306
1284 Py_XINCREF(get); 1307 Py_XINCREF(get);
1285 Py_XINCREF(set); 1308 Py_XINCREF(set);
1286 Py_XINCREF(del); 1309 Py_XINCREF(del);
1287 Py_XINCREF(doc); 1310 Py_XINCREF(doc);
1311 Py_INCREF(Py_False);
1288 1312
1289 prop->prop_get = get; 1313 prop->prop_get = get;
1290 prop->prop_set = set; 1314 prop->prop_set = set;
1291 prop->prop_del = del; 1315 prop->prop_del = del;
1292 prop->prop_doc = doc; 1316 prop->prop_doc = doc;
1317 prop->prop_isabstract = Py_False;
1293 prop->getter_doc = 0; 1318 prop->getter_doc = 0;
1294 1319
1295 /* if no docstring given and the getter has one, use that one */ 1320 /* if no docstring given and the getter has one, use that one */
1296 if ((doc == NULL || doc == Py_None) && get != NULL) { 1321 if ((doc == NULL || doc == Py_None) && get != NULL) {
1297 PyObject *get_doc = PyObject_GetAttrString(get, "__doc__"); 1322 PyObject *get_doc = PyObject_GetAttrString(get, "__doc__");
1298 if (get_doc) { 1323 if (get_doc) {
1299 if (Py_TYPE(self) == &PyProperty_Type) { 1324 if (Py_TYPE(self) == &PyProperty_Type) {
1300 Py_XDECREF(prop->prop_doc); 1325 Py_XDECREF(prop->prop_doc);
1301 prop->prop_doc = get_doc; 1326 prop->prop_doc = get_doc;
1302 } 1327 }
1303 else { 1328 else {
1304 /* If this is a property subclass, put __doc__ 1329 /* If this is a property subclass, put __doc__
1305 in dict of the subclass instance instead, 1330 in dict of the subclass instance instead,
1306 otherwise it gets shadowed by __doc__ in the 1331 otherwise it gets shadowed by __doc__ in the
1307 class's dict. */ 1332 class's dict. */
1308 int err = PyObject_SetAttrString(self, "__doc__", get_doc); 1333 int err = PyObject_SetAttrString(self, "__doc__", get_doc);
1309 Py_DECREF(get_doc); 1334 Py_DECREF(get_doc);
1310 if (err < 0) 1335 if (err < 0)
1311 return -1; 1336 return -1;
1312 } 1337 }
1313 prop->getter_doc = 1; 1338 prop->getter_doc = 1;
1314 } 1339 }
1315 else if (PyErr_ExceptionMatches(PyExc_Exception)) { 1340 else if (PyErr_ExceptionMatches(PyExc_Exception)) {
1316 PyErr_Clear(); 1341 PyErr_Clear();
1317 } 1342 }
1318 else { 1343 else {
1319 return -1; 1344 return -1;
1320 } 1345 }
1321 } 1346 }
1347
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);
1322 1352
1323 return 0; 1353 return 0;
1324 } 1354 }
1325 1355
1326 PyDoc_STRVAR(property_doc, 1356 PyDoc_STRVAR(property_doc,
1327 "property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n" 1357 "property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n"
1328 "\n" 1358 "\n"
1329 "fget is a function to be used for getting an attribute value, and likewise\n" 1359 "fget is a function to be used for getting an attribute value, and likewise\n"
1330 "fset is a function for setting, and fdel a function for del'ing, an\n" 1360 "fset is a function for setting, and fdel a function for del'ing, an\n"
1331 "attribute. Typical use is to define a managed attribute x:\n" 1361 "attribute. Typical use is to define a managed attribute x:\n"
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1392 0, /* tp_base */ 1422 0, /* tp_base */
1393 0, /* tp_dict */ 1423 0, /* tp_dict */
1394 property_descr_get, /* tp_descr_get */ 1424 property_descr_get, /* tp_descr_get */
1395 property_descr_set, /* tp_descr_set */ 1425 property_descr_set, /* tp_descr_set */
1396 0, /* tp_dictoffset */ 1426 0, /* tp_dictoffset */
1397 property_init, /* tp_init */ 1427 property_init, /* tp_init */
1398 PyType_GenericAlloc, /* tp_alloc */ 1428 PyType_GenericAlloc, /* tp_alloc */
1399 PyType_GenericNew, /* tp_new */ 1429 PyType_GenericNew, /* tp_new */
1400 PyObject_GC_Del, /* tp_free */ 1430 PyObject_GC_Del, /* tp_free */
1401 }; 1431 };
OLDNEW
« Lib/test/test_abc.py ('K') | « Lib/test/test_abc.py ('k') | no next file » | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+