mirror of https://github.com/python/cpython
[3.13] bpo-24766: doc= argument to subclasses of property not handled correctly (GH-2487) (GH-120305)
(cherry picked from commit 4829522b8d
)
Co-authored-by: E. M. Bray <erik.bray@lri.fr>
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
parent
7993268beb
commit
f386cc9620
|
@ -463,6 +463,40 @@ class PropertySubclassTests(unittest.TestCase):
|
||||||
self.assertEqual(p.__doc__, "user")
|
self.assertEqual(p.__doc__, "user")
|
||||||
self.assertEqual(p2.__doc__, "user")
|
self.assertEqual(p2.__doc__, "user")
|
||||||
|
|
||||||
|
@unittest.skipIf(sys.flags.optimize >= 2,
|
||||||
|
"Docstrings are omitted with -O2 and above")
|
||||||
|
def test_prefer_explicit_doc(self):
|
||||||
|
# Issue 25757: subclasses of property lose docstring
|
||||||
|
self.assertEqual(property(doc="explicit doc").__doc__, "explicit doc")
|
||||||
|
self.assertEqual(PropertySub(doc="explicit doc").__doc__, "explicit doc")
|
||||||
|
|
||||||
|
class Foo:
|
||||||
|
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")
|
||||||
|
|
||||||
|
def test_property_no_doc_on_getter(self):
|
||||||
|
# If a property's getter has no __doc__ then the property's doc should
|
||||||
|
# be None; test that this is consistent with subclasses as well; see
|
||||||
|
# GH-2487
|
||||||
|
class NoDoc:
|
||||||
|
@property
|
||||||
|
def __doc__(self):
|
||||||
|
raise AttributeError
|
||||||
|
|
||||||
|
self.assertEqual(property(NoDoc()).__doc__, None)
|
||||||
|
self.assertEqual(PropertySub(NoDoc()).__doc__, None)
|
||||||
|
|
||||||
@unittest.skipIf(sys.flags.optimize >= 2,
|
@unittest.skipIf(sys.flags.optimize >= 2,
|
||||||
"Docstrings are omitted with -O2 and above")
|
"Docstrings are omitted with -O2 and above")
|
||||||
def test_property_setter_copies_getter_docstring(self):
|
def test_property_setter_copies_getter_docstring(self):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fix handling of ``doc`` argument to subclasses of ``property``.
|
|
@ -1859,22 +1859,9 @@ property_init_impl(propertyobject *self, PyObject *fget, PyObject *fset,
|
||||||
/* if no docstring given and the getter has one, use that one */
|
/* if no docstring given and the getter has one, use that one */
|
||||||
else if (fget != NULL) {
|
else if (fget != NULL) {
|
||||||
int rc = PyObject_GetOptionalAttr(fget, &_Py_ID(__doc__), &prop_doc);
|
int rc = PyObject_GetOptionalAttr(fget, &_Py_ID(__doc__), &prop_doc);
|
||||||
if (rc <= 0) {
|
if (rc < 0) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
if (!Py_IS_TYPE(self, &PyProperty_Type) &&
|
|
||||||
prop_doc != NULL && prop_doc != Py_None) {
|
|
||||||
// This oddity preserves the long existing behavior of surfacing
|
|
||||||
// an AttributeError when using a dict-less (__slots__) property
|
|
||||||
// subclass as a decorator on a getter method with a docstring.
|
|
||||||
// See PropertySubclassTest.test_slots_docstring_copy_exception.
|
|
||||||
int err = PyObject_SetAttr(
|
|
||||||
(PyObject *)self, &_Py_ID(__doc__), prop_doc);
|
|
||||||
if (err < 0) {
|
|
||||||
Py_DECREF(prop_doc); // release our new reference.
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (prop_doc == Py_None) {
|
if (prop_doc == Py_None) {
|
||||||
prop_doc = NULL;
|
prop_doc = NULL;
|
||||||
Py_DECREF(Py_None);
|
Py_DECREF(Py_None);
|
||||||
|
@ -1902,7 +1889,9 @@ property_init_impl(propertyobject *self, PyObject *fget, PyObject *fset,
|
||||||
Py_DECREF(prop_doc);
|
Py_DECREF(prop_doc);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
assert(PyErr_Occurred());
|
assert(PyErr_Occurred());
|
||||||
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
if (!self->getter_doc &&
|
||||||
|
PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||||
|
{
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
// https://github.com/python/cpython/issues/98963#issuecomment-1574413319
|
// https://github.com/python/cpython/issues/98963#issuecomment-1574413319
|
||||||
// Python silently dropped this doc assignment through 3.11.
|
// Python silently dropped this doc assignment through 3.11.
|
||||||
|
|
Loading…
Reference in New Issue