diff --git a/Lib/test/test_dynamicclassattribute.py b/Lib/test/test_dynamicclassattribute.py index b19be33c72f94b..bc89a2907c6ebf 100644 --- a/Lib/test/test_dynamicclassattribute.py +++ b/Lib/test/test_dynamicclassattribute.py @@ -4,6 +4,7 @@ import abc import sys import unittest +from test import support from types import DynamicClassAttribute class PropertyBase(Exception): @@ -195,6 +196,16 @@ def __init__(self): Okay2.color self.assertEqual(Okay2().color, 'magenta') + @support.requires_docstrings + def test_empty_docstring(self): + attr = DynamicClassAttribute(fget=None, fset=None, fdel=None, doc='') + self.assertEqual(attr.__doc__, '') + def fget(): + """fget's docstring""" + attr_with_fget = DynamicClassAttribute(fget=fget, doc='') + self.assertEqual(attr_with_fget.__doc__, '') + attr_no_doc = DynamicClassAttribute(fget=None) + self.assertIsNone(attr_no_doc.__doc__) # Issue 5890: subclasses of DynamicClassAttribute do not preserve method __doc__ strings class PropertySub(DynamicClassAttribute): diff --git a/Lib/types.py b/Lib/types.py index f96c75b46daba7..d3f1b61b8b58cf 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -210,9 +210,12 @@ def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel + overwrite_doc = doc is None + if doc is None and fget is not None: + doc = fget.__doc__ # next two lines make DynamicClassAttribute act the same as property - self.__doc__ = doc or fget.__doc__ - self.overwrite_doc = doc is None + self.__doc__ = doc + self.overwrite_doc = overwrite_doc # support for abstract methods self.__isabstractmethod__ = bool(getattr(fget, '__isabstractmethod__', False)) diff --git a/Misc/NEWS.d/next/Library/2025-11-08-21-01-46.gh-issue-140972.v960ZZ.rst b/Misc/NEWS.d/next/Library/2025-11-08-21-01-46.gh-issue-140972.v960ZZ.rst new file mode 100644 index 00000000000000..6ce015018db851 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-11-08-21-01-46.gh-issue-140972.v960ZZ.rst @@ -0,0 +1,3 @@ +Now empty docstrings passed to :func:`types.DynamicClassAttribute` are +preserved when ``fget`` is ``None``; previously ``NoneType.__doc__`` was used +incorrectly.