8000 Fixes bpo-24766: doc= argument to subclasses of property not handled … · python/cpython@7b6097e · GitHub
[go: up one dir, main page]

Skip to content

Commit 7b6097e

Browse files
committed
Fixes bpo-24766: doc= argument to subclasses of property not handled correctly
1 parent c8fb58b commit 7b6097e

File tree

2 files changed

+36
-14
lines changed

2 files changed

+36
-14
lines changed

Lib/test/test_property.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,28 @@ def spam(self):
207207
Foo.spam.__doc__,
208208
"spam wrapped in property subclass")
209209

210+
@unittest.skipIf(sys.flags.optimize >= 2,
211+
"Docstrings are omitted with -O2 and above")
212+
def test_prefer_explicit_doc(self):
213+
# Issue 25757: subclasses of property lose docstring
214+
self.assertEqual(property(doc="explicit doc").__doc__, "explicit doc")
215+
self.assertEqual(PropertySub(doc="explicit doc").__doc__, "explicit doc")
216+
217+
class Foo:
218+
spam = PropertySub(doc="spam explicit doc")
219+
220+
@spam.getter
221+
def spam(self):
222+
"""ignored as doc already set"""
223+
return 1
224+
225+
def _stuff_getter(self):
226+
"""ignored as doc set directly"""
227+
stuff = PropertySub(doc="stuff doc argument", fget=_stuff_getter)
228+
229+
self.assertEqual(Foo.spam.__doc__, "spam explicit doc")
230+
self.assertEqual(Foo.stuff.__doc__, "stuff doc argument")
231+
210232
@unittest.skipIf(sys.flags.optimize >= 2,
211233
"Docstrings are omitted with -O2 and above")
212234
def test_property_setter_copies_getter_docstring(self):

Objects/descrobject.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,6 +1504,8 @@ property_init_impl(propertyobject *self, PyObject *fget, PyObject *fset,
15041504
PyObject *fdel, PyObject *doc)
15051505
/*[clinic end generated code: output=01a960742b692b57 input=dfb5dbbffc6932d5]*/
15061506
{
1507+
_Py_IDENTIFIER(__doc__);
1508+
15071509
if (fget == Py_None)
15081510
fget = NULL;
15091511
if (fset == Py_None)
@@ -1524,32 +1526,30 @@ property_init_impl(propertyobject *self, PyObject *fget, PyObject *fset,
15241526

15251527
/* if no docstring given and the getter has one, use that one */
15261528
if ((doc == NULL || doc == Py_None) && fget != NULL) {
1527-
_Py_IDENTIFIER(__doc__);
15281529
PyObject *get_doc = _PyObject_GetAttrId(fget, &PyId___doc__);
15291530
if (get_doc) {
1530-
if (Py_TYPE(self) == &PyProperty_Type) {
1531-
Py_XSETREF(self->prop_doc, get_doc);
1532-
}
1533-
else {
1534-
/* If this is a property subclass, put __doc__
1535-
in dict of the subclass instance instead,
1536-
otherwise it gets shadowed by __doc__ in the
1537-
class's dict. */
1538-
int err = _PyObject_SetAttrId((PyObject *)self, &PyId___doc__, get_doc);
1539-
Py_DECREF(get_doc);
1540-
if (err < 0)
1541-
return -1;
1542-
}
1531+
Py_XSETREF(self->prop_doc, get_doc);
15431532
self->getter_doc = 1;
15441533
}
15451534
else if (PyErr_ExceptionMatches(PyExc_Exception)) {
15461535
PyErr_Clear();
15471536
}
15481537
else {
1538+
Py_DECREF(get_doc);
15491539
return -1;
15501540
}
15511541
}
15521542

1543+
/* If this is a property subclass, put __doc__ in dict of the subclass
1544+
instance as well, otherwise it gets shadowed by __doc__ in the
1545+
class's dict. */
1546+
if (Py_TYPE(self) != &PyProperty_Type) {
1547+
int err = _PyObject_SetAttrId((PyObject *)self, &PyId___doc__,
1548+
self->prop_doc);
1549+
if (err < 0)
1550+
return -1;
1551+
}
1552+
15531553
return 0;
15541554
}
15551555

0 commit comments

Comments
 (0)
0