diff --git a/Lib/test/test_property.py b/Lib/test/test_property.py --- a/Lib/test/test_property.py +++ b/Lib/test/test_property.py @@ -209,6 +209,26 @@ @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") + def test_prefer_explicit_doc(self): + self.assertEqual(property(doc="explicit doc").__doc__, "explicit doc") + self.assertEqual(PropertySub(doc="explicit doc").__doc__, "explicit doc") + + class Foo(object): + spam = PropertySub(doc="spam explicit doc") + @spam.getter + def spam(self): + """ignored as doc already set""" + return 1 + + def _stuff_getter(self): + """ignored as doc set directly""" + stuff = PropertySub(doc="stuff doc argument", fget=_stuff_getter) + + self.assertEqual(Foo.spam.__doc__, "spam explicit doc") + self.assertEqual(Foo.stuff.__doc__, "stuff doc argument") + + @unittest.skipIf(sys.flags.optimize >= 2, + "Docstrings are omitted with -O2 and above") def test_property_setter_copies_getter_docstring(self): class Foo(object): def __init__(self): self._spam = 1 diff --git a/Objects/descrobject.c b/Objects/descrobject.c --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1477,6 +1477,7 @@ static int property_init(PyObject *self, PyObject *args, PyObject *kwds) { + _Py_IDENTIFIER(__doc__); PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; propertyobject *prop = (propertyobject *)self; @@ -1505,31 +1506,22 @@ /* if no docstring given and the getter has one, use that one */ if ((doc == NULL || doc == Py_None) && get != NULL) { - _Py_IDENTIFIER(__doc__); PyObject *get_doc = _PyObject_GetAttrId(get, &PyId___doc__); - if (get_doc) { - if (Py_TYPE(self) == &PyProperty_Type) { - Py_XDECREF(prop->prop_doc); - prop->prop_doc = get_doc; - } - else { - /* If this is a property subclass, put __doc__ - in dict of the subclass instance instead, - otherwise it gets shadowed by __doc__ in the - class's dict. */ - int err = _PyObject_SetAttrId(self, &PyId___doc__, get_doc); - Py_DECREF(get_doc); - if (err < 0) - return -1; - } - prop->getter_doc = 1; - } - else if (PyErr_ExceptionMatches(PyExc_Exception)) { - PyErr_Clear(); - } - else { + if (!get_doc) return -1; - } + + Py_XDECREF(prop->prop_doc); + prop->prop_doc = get_doc; + prop->getter_doc = 1; + } + + /* If this is a property subclass, put __doc__ in dict of the subclass + instance as well, otherwise it gets shadowed by __doc__ in the + class's dict. */ + if (Py_TYPE(self) != &PyProperty_Type) { + int err = _PyObject_SetAttrId(self, &PyId___doc__, prop->prop_doc); + if (err < 0) + return -1; } return 0;