diff -r dfceb98767c0 Doc/library/abc.rst --- a/Doc/library/abc.rst Sat Mar 19 17:47:26 2011 +0800 +++ b/Doc/library/abc.rst Sat Mar 19 14:46:35 2011 -0400 @@ -163,6 +163,29 @@ super-call in a framework that uses cooperative multiple-inheritance. + .. versionchanged:: 3.3 + The :func:`property` definition has been extended to allow + abstract properties to be specified using + :func:`abstractmethod`:: + + class C(metaclass=ABCMeta): + @property + @abstractmethod + def x(self): + ... + @x.setter + @abstractmethod + def x(self, val): + ... + + @abstractmethod + def gety(self): + ... + @abstractmethod + def sety(self): + ... + y = property(gety, sety) + .. decorator:: abstractclassmethod(function) @@ -220,6 +243,8 @@ def setx(self, value): ... x = abstractproperty(getx, setx) + .. deprecated:: 3.3 + .. rubric:: Footnotes diff -r dfceb98767c0 Lib/abc.py --- a/Lib/abc.py Sat Mar 19 17:47:26 2011 +0800 +++ b/Lib/abc.py Sat Mar 19 14:46:35 2011 -0400 @@ -89,6 +89,11 @@ def setx(self, value): ... x = abstractproperty(getx, setx) """ + warnings.warn( + "abstractproperty will be removed in future versions. " + "Use 'property' in conjunction with 'abstractmethod' instead.", + DeprecationWarning, stacklevel=2 + ) __isabstractmethod__ = True diff -r dfceb98767c0 Lib/test/test_abc.py --- a/Lib/test/test_abc.py Sat Mar 19 17:47:26 2011 +0800 +++ b/Lib/test/test_abc.py Sat Mar 19 14:46:35 2011 -0400 @@ -34,6 +34,30 @@ def foo(self): return super().foo self.assertEqual(D().foo, 3) + def test_abstractmethod_with_property_builtin(self): + class C(metaclass=abc.ABCMeta): + @Property + @abc.abstractmethod + def x(self): + pass + @x.setter + @abc.abstractmethod + def x(self, val): + pass + self.assertRaises(TypeError, C) + + class D(C): + @C.x.getter + def x(self): + return 1 + self.assertRaises(TypeError, D) + + class E(D): + @D.x.setter + def x(self, val): + pass + self.assertEqual(E().x, 1) + def test_abstractclassmethod_basics(self): @abc.abstractclassmethod def foo(cls): pass diff -r dfceb98767c0 Objects/descrobject.c --- a/Objects/descrobject.c Sat Mar 19 17:47:26 2011 +0800 +++ b/Objects/descrobject.c Sat Mar 19 14:46:35 2011 -0400 @@ -1091,6 +1091,10 @@ self.__set = fset self.__del = fdel self.__doc__ = doc + for f in (fget, fset, fdel): + if getattr(f, '__isabstractmethod__', False): + self.__isabstractmethod__ = True + break def __get__(self, inst, type=None): if inst is None: @@ -1117,6 +1121,7 @@ PyObject *prop_set; PyObject *prop_del; PyObject *prop_doc; + PyObject *prop_isabstract; int getter_doc; } propertyobject; @@ -1128,6 +1133,8 @@ {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY}, {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY}, {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY}, + {"__isabstractmethod__", T_OBJECT, + offsetof(propertyobject, prop_isabstract), READONLY}, {0} }; @@ -1180,6 +1187,7 @@ Py_XDECREF(gs->prop_set); Py_XDECREF(gs->prop_del); Py_XDECREF(gs->prop_doc); + Py_XDECREF(gs->prop_isabstract); self->ob_type->tp_free(self); } @@ -1213,7 +1221,7 @@ PyErr_SetString(PyExc_AttributeError, value == NULL ? "can't delete attribute" : - "can't set attribute"); + "can't set attribute"); return -1; } if (value == NULL) @@ -1263,6 +1271,21 @@ return new; } +static void +property_identify_abstract_method(PyObject *self, PyObject *method) +{ + /* Set self.__isabstractmethod__ if method is abstract */ + if (method != NULL){ + PyObject *is_abstract = PyObject_GetAttrString(method, + "__isabstractmethod__"); + if (PyObject_IsTrue(is_abstract) > 0){ + Py_INCREF(Py_True); + PyObject_SetAttrString(self, "__isabstractmethod__", Py_True); + } + Py_DECREF(is_abstract); + } +} + static int property_init(PyObject *self, PyObject *args, PyObject *kwds) { @@ -1285,11 +1308,13 @@ Py_XINCREF(set); Py_XINCREF(del); Py_XINCREF(doc); + Py_INCREF(Py_False); prop->prop_get = get; prop->prop_set = set; prop->prop_del = del; prop->prop_doc = doc; + prop->prop_isabstract = Py_False; prop->getter_doc = 0; /* if no docstring given and the getter has one, use that one */ @@ -1320,6 +1345,11 @@ } } + /* set __isabstractmethod__ if fget, fset, or fdel are abstract methods */ + property_identify_abstract_method(self, get); + property_identify_abstract_method(self, set); + property_identify_abstract_method(self, del); + return 0; }