From eac503aeac6fedc81001b9e1136957d45b9a2c51 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Wed, 13 May 2015 01:09:59 -0700 Subject: Issue #24064: Property() docstrings are now writeable. (Patch by Berker Peksag.) --- Doc/library/collections.rst | 9 +++++++++ Doc/whatsnew/3.5.rst | 16 ++++++++++++++++ Lib/test/test_collections.py | 8 ++++++++ Lib/test/test_descr.py | 5 ++++- Lib/test/test_property.py | 22 ++++++++++++++++++++++ Misc/NEWS | 3 +++ Objects/descrobject.c | 2 +- 7 files changed, 63 insertions(+), 2 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index dd6395d..892f05d 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -924,6 +924,15 @@ create a new named tuple type from the :attr:`_fields` attribute: >>> Point3D = namedtuple('Point3D', Point._fields + ('z',)) +Docstrings can be customized by making direct assignments to the ``__doc__`` +fields: + + >>> Book = namedtuple('Book', ['id', 'title', 'authors']) + >>> Book.__doc__ = 'Hardcover book in active collection' + >>> Book.id = '13-digit ISBN' + >>> Book.title = 'Title of first printing' + >>> Book.author = 'List of authors sorted by last name' + Default values can be implemented by using :meth:`_replace` to customize a prototype instance: diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 48d871a..a29ff10 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -234,6 +234,10 @@ Some smaller changes made to the core Python language are: * New Kazakh :ref:`codec ` ``kz1048``. (Contributed by Serhiy Storchaka in :issue:`22682`.) +* Property docstrings are now writable. This is especially useful for + :func:`collections.namedtuple` docstrings. + (Contributed by Berker Peksag in :issue:`24064`.) + * New Tajik :ref:`codec ` ``koi8_t``. (Contributed by Serhiy Storchaka in :issue:`22681`.) @@ -283,6 +287,18 @@ code the full chained traceback, just like the interactive interpreter. (Contributed by Claudiu Popa in :issue:`17442`.) +collections +----------- + +* You can now update docstrings produced by :func:`collections.namedtuple`:: + + Point = namedtuple('Point', ['x', 'y']) + Point.__doc__ = 'ordered pair' + Point.x.__doc__ = 'abscissa' + Point.y.__doc__ = 'ordinate' + + (Contributed by Berker Peksag in :issue:`24064`.) + compileall ---------- diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index ad94fdd..2bb5538 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -199,6 +199,14 @@ class TestNamedTuple(unittest.TestCase): Point = namedtuple('Point', 'x y') self.assertEqual(Point.__doc__, 'Point(x, y)') + @unittest.skipIf(sys.flags.optimize >= 2, + "Docstrings are omitted with -O2 and above") + def test_doc_writable(self): + Point = namedtuple('Point', 'x y') + self.assertEqual(Point.x.__doc__, 'Alias for field number 0') + Point.x.__doc__ = 'docstring for Point.x' + self.assertEqual(Point.x.__doc__, 'docstring for Point.x') + def test_name_fixer(self): for spec, renamed in [ [('efg', 'g%hi'), ('efg', '_1')], # field with non-alpha char diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 9f3d34d..80a526d 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -2022,7 +2022,7 @@ order (MRO) for bases """ self.assertIs(raw.fset, C.__dict__['setx']) self.assertIs(raw.fdel, C.__dict__['delx']) - for attr in "__doc__", "fget", "fset", "fdel": + for attr in "fget", "fset", "fdel": try: setattr(raw, attr, 42) except AttributeError as msg: @@ -2033,6 +2033,9 @@ order (MRO) for bases """ self.fail("expected AttributeError from trying to set readonly %r " "attr on a property" % attr) + raw.__doc__ = 42 + self.assertEqual(raw.__doc__, 42) + class D(object): __getitem__ = property(lambda s: 1/0) diff --git a/Lib/test/test_property.py b/Lib/test/test_property.py index e72eb55..5addd36 100644 --- a/Lib/test/test_property.py +++ b/Lib/test/test_property.py @@ -76,6 +76,13 @@ class PropertyNewGetter(object): """new docstring""" return 8 +class PropertyWritableDoc(object): + + @property + def spam(self): + """Eggs""" + return "eggs" + class PropertyTests(unittest.TestCase): def test_property_decorator_baseclass(self): # see #1620 @@ -150,6 +157,21 @@ class PropertyTests(unittest.TestCase): foo = property(foo) C.foo.__isabstractmethod__ + @unittest.skipIf(sys.flags.optimize >= 2, + "Docstrings are omitted with -O2 and above") + def test_property_builtin_doc_writable(self): + p = property(doc='basic') + self.assertEqual(p.__doc__, 'basic') + p.__doc__ = 'extended' + self.assertEqual(p.__doc__, 'extended') + + @unittest.skipIf(sys.flags.optimize >= 2, + "Docstrings are omitted with -O2 and above") + def test_property_decorator_doc_writable(self): + sub = PropertyWritableDoc() + self.assertEqual(sub.__class__.spam.__doc__, 'Eggs') + sub.__class__.spam.__doc__ = 'Spam' + self.assertEqual(sub.__class__.spam.__doc__, 'Spam') # Issue 5890: subclasses of property do not preserve method __doc__ strings class PropertySub(property): diff --git a/Misc/NEWS b/Misc/NEWS index 58a1daa..20cc9d7 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -45,6 +45,9 @@ Library - Issue #22486: Added the math.gcd() function. The fractions.gcd() function now is deprecated. Based on patch by Mark Dickinson. +- Issue #24064: Property() docstrings are now writeable. + (Patch by Berker Peksag.) + - Issue #22681: Added support for the koi8_t encoding. - Issue #22682: Added support for the kz1048 encoding. diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 822fb41..906f76d 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1313,7 +1313,7 @@ static PyMemberDef property_members[] = { {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY}, {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY}, {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY}, - {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY}, + {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), 0}, {0} }; -- cgit v0.12