From 19d5c42b09a57c5d93ee9cd391ab21b8ea55ba90 Mon Sep 17 00:00:00 2001 From: lincolnj1 Date: Wed, 12 Mar 2025 10:41:51 -0700 Subject: [PATCH 01/12] attempted fix of issue #131116. Test case failing on non changed parts --- Lib/inspect.py | 6 ++++++ Lib/test/test_inspect/inspect_fodder.py | 10 ++++++++++ Lib/test/test_inspect/test_inspect.py | 3 +++ 3 files changed, 19 insertions(+) diff --git a/Lib/inspect.py b/Lib/inspect.py index f143c89674b7b2..30d5e4c0ebd7a6 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -747,6 +747,12 @@ def _finddoc(obj): cls = _findclass(obj.fget) if cls is None or getattr(cls, name) is not obj: return None + # Should be tested before ismethoddescriptor() + elif isinstance(obj, functools.cached_property): + name = obj.attrname + cls = _findclass(obj.func) + if cls is None or getattr(cls, name) is not obj: + return None elif ismethoddescriptor(obj) or isdatadescriptor(obj): name = obj.__name__ cls = obj.__objclass__ diff --git a/Lib/test/test_inspect/inspect_fodder.py b/Lib/test/test_inspect/inspect_fodder.py index febd54c86fe1d1..a000280916ce6d 100644 --- a/Lib/test/test_inspect/inspect_fodder.py +++ b/Lib/test/test_inspect/inspect_fodder.py @@ -2,6 +2,7 @@ 'A module docstring.' import inspect +from functools import cached_property # line 5 # line 7 @@ -50,6 +51,11 @@ def contradiction(self): 'The automatic gainsaying.' pass + @cached_property + def foo(self): + "StupidGit.foo docstring" + pass + # line 53 class MalodorousPervert(StupidGit): def abuse(self, a, b, c): @@ -59,6 +65,10 @@ def abuse(self, a, b, c): def contradiction(self): pass + @cached_property + def foo(self): + pass + Tit = MalodorousPervert class ParrotDroppings: diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 6a562108c3a34b..49c170617aeaf4 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -652,6 +652,9 @@ def test_getdoc(self): 'measured in kilowatts') self.assertEqual(inspect.getdoc(SlotUser.distance), 'measured in kilometers') + print('new test', file=sys.stderr) + self.assertEqual(inspect.getdoc(mod.MalodorousPervert.foo), + inspect.getdoc(mod.StupidGit.foo)) @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") From 02ec2c1ca9a704e040dd3127d5325a4357effa27 Mon Sep 17 00:00:00 2001 From: lincolnj1 Date: Wed, 12 Mar 2025 11:02:40 -0700 Subject: [PATCH 02/12] Moved new test fodder to seperate file to fix errors --- Lib/test/test_inspect/inspect_fodder3.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Lib/test/test_inspect/inspect_fodder3.py diff --git a/Lib/test/test_inspect/inspect_fodder3.py b/Lib/test/test_inspect/inspect_fodder3.py new file mode 100644 index 00000000000000..e0bb3a390ed88e --- /dev/null +++ b/Lib/test/test_inspect/inspect_fodder3.py @@ -0,0 +1,12 @@ +from functools import cached_property + +class Parent: + @cached_property + def foo(self): + "this is the docstring for foo" + pass + +class Child(Parent): + @cached_property + def foo(self): + pass From 8786c3c29a62aa3d8a68820f7239c5dc4a7f9257 Mon Sep 17 00:00:00 2001 From: lincolnj1 Date: Wed, 12 Mar 2025 11:09:17 -0700 Subject: [PATCH 03/12] Cleaned workspace and actually added the changed files this time --- Lib/test/test_inspect/inspect_fodder.py | 10 ---------- Lib/test/test_inspect/test_inspect.py | 5 +++-- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_inspect/inspect_fodder.py b/Lib/test/test_inspect/inspect_fodder.py index a000280916ce6d..febd54c86fe1d1 100644 --- a/Lib/test/test_inspect/inspect_fodder.py +++ b/Lib/test/test_inspect/inspect_fodder.py @@ -2,7 +2,6 @@ 'A module docstring.' import inspect -from functools import cached_property # line 5 # line 7 @@ -51,11 +50,6 @@ def contradiction(self): 'The automatic gainsaying.' pass - @cached_property - def foo(self): - "StupidGit.foo docstring" - pass - # line 53 class MalodorousPervert(StupidGit): def abuse(self, a, b, c): @@ -65,10 +59,6 @@ def abuse(self, a, b, c): def contradiction(self): pass - @cached_property - def foo(self): - pass - Tit = MalodorousPervert class ParrotDroppings: diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 49c170617aeaf4..5f3242d9afc5a8 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -46,6 +46,7 @@ from test.test_inspect import inspect_fodder as mod from test.test_inspect import inspect_fodder2 as mod2 +from test.test_inspect import inspect_fodder3 as mod3 from test.test_inspect import inspect_stringized_annotations from test.test_inspect import inspect_deferred_annotations @@ -653,8 +654,8 @@ def test_getdoc(self): self.assertEqual(inspect.getdoc(SlotUser.distance), 'measured in kilometers') print('new test', file=sys.stderr) - self.assertEqual(inspect.getdoc(mod.MalodorousPervert.foo), - inspect.getdoc(mod.StupidGit.foo)) + self.assertEqual(inspect.getdoc(mod3.Parent.foo), + inspect.getdoc(mod3.Child.foo)) @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") From 5772f7b2aa9326c0ae34f3d4cd9d6f7574eb4c6c Mon Sep 17 00:00:00 2001 From: lincolnj1 Date: Wed, 12 Mar 2025 11:47:10 -0700 Subject: [PATCH 04/12] Seperated new tests into new test case --- Lib/test/test_inspect/test_inspect.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 5f3242d9afc5a8..a7be4c61d9c2a0 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -653,9 +653,6 @@ def test_getdoc(self): 'measured in kilowatts') self.assertEqual(inspect.getdoc(SlotUser.distance), 'measured in kilometers') - print('new test', file=sys.stderr) - self.assertEqual(inspect.getdoc(mod3.Parent.foo), - inspect.getdoc(mod3.Child.foo)) @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") @@ -669,6 +666,10 @@ def test_getdoc_inherited(self): self.assertEqual(inspect.getdoc(mod.FesteringGob.contradiction), 'The automatic gainsaying.') + def test_getdoc_inherited_cached_property(self): + self.assertEqual(inspect.getdoc(mod3.Parent.foo), + inspect.getdoc(mod3.Child.foo)) + @unittest.skipIf(MISSING_C_DOCSTRINGS, "test requires docstrings") def test_finddoc(self): finddoc = inspect._finddoc From 24060559fe45770fee040917438c1e86d04c8f69 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 12 Mar 2025 18:57:11 +0000 Subject: [PATCH 05/12] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-03-12-18-57-10.gh-issue-131116.uTpwXZ.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-03-12-18-57-10.gh-issue-131116.uTpwXZ.rst diff --git a/Misc/NEWS.d/next/Library/2025-03-12-18-57-10.gh-issue-131116.uTpwXZ.rst b/Misc/NEWS.d/next/Library/2025-03-12-18-57-10.gh-issue-131116.uTpwXZ.rst new file mode 100644 index 00000000000000..123da463a945c1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-12-18-57-10.gh-issue-131116.uTpwXZ.rst @@ -0,0 +1 @@ +inspect.getdoc(), if run on a cached_property that does not define a docstring but inherits from a class that did define a docstring, will now return the inherited docstring rather than None. From d61ab34248a43482b204c3e6ca4e102df3a3c50d Mon Sep 17 00:00:00 2001 From: lincolnj1 Date: Mon, 31 Mar 2025 10:41:33 -0700 Subject: [PATCH 06/12] Added more tests and versionchanged to Doc --- Doc/library/inspect.rst | 3 ++ Lib/test/test_inspect/inspect_fodder3.py | 28 +++++++++++++++++-- Lib/test/test_inspect/test_inspect.py | 14 ++++++++-- ...-03-12-18-57-10.gh-issue-131116.uTpwXZ.rst | 2 +- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index e8d1176f477866..c7bb5ab1e8b5d0 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -627,6 +627,9 @@ Retrieving source code .. versionchanged:: 3.5 Documentation strings are now inherited if not overridden. + .. versionchanged:: next + Now correctly returns an inherited docstring on :class:`~functools.cached_property` objects if not overridden. + .. function:: getcomments(object) diff --git a/Lib/test/test_inspect/inspect_fodder3.py b/Lib/test/test_inspect/inspect_fodder3.py index e0bb3a390ed88e..c241aa572d86c8 100644 --- a/Lib/test/test_inspect/inspect_fodder3.py +++ b/Lib/test/test_inspect/inspect_fodder3.py @@ -1,12 +1,34 @@ from functools import cached_property -class Parent: +# Docstring in parent, inherited in child +class ParentInheritDoc: @cached_property def foo(self): - "this is the docstring for foo" + "docstring for foo defined in parent" + +class ChildInheritDoc(ParentInheritDoc): + @cached_property + def foo(self): + pass + +# Redine foo as something other than cached_property +class ChildPropertyFoo(ParentInheritDoc): + @property + def foo(self): + "docstring for the property foo" pass -class Child(Parent): +class ChildMethodFoo(ParentInheritDoc): + def foo(self): + "docstring for the method foo" + +# Docstring in child but not parent +class ParentNoDoc: @cached_property def foo(self): pass + +class ChildDefineDoc(ParentNoDoc): + @cached_property + def foo(self): + "docstring for foo defined in child" diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index f8c8fa0a6281cb..c102be61348005 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -667,8 +667,18 @@ def test_getdoc_inherited(self): 'The automatic gainsaying.') def test_getdoc_inherited_cached_property(self): - self.assertEqual(inspect.getdoc(mod3.Parent.foo), - inspect.getdoc(mod3.Child.foo)) + self.assertEqual(inspect.getdoc(mod3.ChildInheritDoc.foo), + 'docstring for foo defined in parent') + + def test_getdoc_redefine_cached_property_as_other(self): + self.assertEqual(inspect.getdoc(mod3.ChildPropertyFoo.foo), + 'docstring for the property foo') + self.assertEqual(inspect.getdoc(mod3.ChildMethodFoo.foo), + 'docstring for the method foo') + + def test_getdoc_define_cached_property(self): + self.assertEqual(inspect.getdoc(mod3.ChildDefineDoc.foo), + 'docstring for foo defined in child') @unittest.skipIf(MISSING_C_DOCSTRINGS, "test requires docstrings") def test_finddoc(self): diff --git a/Misc/NEWS.d/next/Library/2025-03-12-18-57-10.gh-issue-131116.uTpwXZ.rst b/Misc/NEWS.d/next/Library/2025-03-12-18-57-10.gh-issue-131116.uTpwXZ.rst index 123da463a945c1..2e9d8b11548a1f 100644 --- a/Misc/NEWS.d/next/Library/2025-03-12-18-57-10.gh-issue-131116.uTpwXZ.rst +++ b/Misc/NEWS.d/next/Library/2025-03-12-18-57-10.gh-issue-131116.uTpwXZ.rst @@ -1 +1 @@ -inspect.getdoc(), if run on a cached_property that does not define a docstring but inherits from a class that did define a docstring, will now return the inherited docstring rather than None. +:func:`inspect.getdoc` now correctly returns an inherited docstring on :class:`~functools.cached_property` objects if none is given in a subclass. From 4b74d4e38cf64e85c2d66be4d55bdf2da6390e23 Mon Sep 17 00:00:00 2001 From: Jacob Austin Lincoln <99031153+lincolnj1@users.noreply.github.com> Date: Tue, 1 Apr 2025 10:55:30 -0700 Subject: [PATCH 07/12] Update Doc/library/inspect.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/inspect.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index c7bb5ab1e8b5d0..32b675a241fa83 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -628,7 +628,8 @@ Retrieving source code Documentation strings are now inherited if not overridden. .. versionchanged:: next - Now correctly returns an inherited docstring on :class:`~functools.cached_property` objects if not overridden. + Documentation strings on :class:`~functools.cached_property` + objects are now inherited if not overriden. .. function:: getcomments(object) From cfe3e99d76897a92ca67d2ad65021611c4ea30b5 Mon Sep 17 00:00:00 2001 From: Jacob Austin Lincoln <99031153+lincolnj1@users.noreply.github.com> Date: Tue, 1 Apr 2025 10:55:43 -0700 Subject: [PATCH 08/12] Update Lib/test/test_inspect/inspect_fodder3.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_inspect/inspect_fodder3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_inspect/inspect_fodder3.py b/Lib/test/test_inspect/inspect_fodder3.py index c241aa572d86c8..b9cfb7c1628e51 100644 --- a/Lib/test/test_inspect/inspect_fodder3.py +++ b/Lib/test/test_inspect/inspect_fodder3.py @@ -31,4 +31,4 @@ def foo(self): class ChildDefineDoc(ParentNoDoc): @cached_property def foo(self): - "docstring for foo defined in child" + """docstring for foo defined in child""" From fa92ad3d7c160f6a6a87cba97e91727aafe0afc1 Mon Sep 17 00:00:00 2001 From: Jacob Austin Lincoln <99031153+lincolnj1@users.noreply.github.com> Date: Tue, 1 Apr 2025 10:55:52 -0700 Subject: [PATCH 09/12] Update Lib/test/test_inspect/inspect_fodder3.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_inspect/inspect_fodder3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_inspect/inspect_fodder3.py b/Lib/test/test_inspect/inspect_fodder3.py index b9cfb7c1628e51..5480f20eebfbd6 100644 --- a/Lib/test/test_inspect/inspect_fodder3.py +++ b/Lib/test/test_inspect/inspect_fodder3.py @@ -20,7 +20,7 @@ def foo(self): class ChildMethodFoo(ParentInheritDoc): def foo(self): - "docstring for the method foo" + """docstring for the method foo""" # Docstring in child but not parent class ParentNoDoc: From d83205ceb41f106c6e13a9e1aee686bd39e57124 Mon Sep 17 00:00:00 2001 From: Jacob Austin Lincoln <99031153+lincolnj1@users.noreply.github.com> Date: Tue, 1 Apr 2025 10:55:59 -0700 Subject: [PATCH 10/12] Update Lib/test/test_inspect/inspect_fodder3.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_inspect/inspect_fodder3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_inspect/inspect_fodder3.py b/Lib/test/test_inspect/inspect_fodder3.py index 5480f20eebfbd6..e5a917e4d24b17 100644 --- a/Lib/test/test_inspect/inspect_fodder3.py +++ b/Lib/test/test_inspect/inspect_fodder3.py @@ -15,7 +15,7 @@ def foo(self): class ChildPropertyFoo(ParentInheritDoc): @property def foo(self): - "docstring for the property foo" + """docstring for the property foo""" pass class ChildMethodFoo(ParentInheritDoc): From c4764fffb8cd345772d0573bea15514149074275 Mon Sep 17 00:00:00 2001 From: Jacob Austin Lincoln <99031153+lincolnj1@users.noreply.github.com> Date: Tue, 1 Apr 2025 10:56:04 -0700 Subject: [PATCH 11/12] Update Lib/test/test_inspect/inspect_fodder3.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_inspect/inspect_fodder3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_inspect/inspect_fodder3.py b/Lib/test/test_inspect/inspect_fodder3.py index e5a917e4d24b17..b96c02f5c8c335 100644 --- a/Lib/test/test_inspect/inspect_fodder3.py +++ b/Lib/test/test_inspect/inspect_fodder3.py @@ -4,7 +4,7 @@ class ParentInheritDoc: @cached_property def foo(self): - "docstring for foo defined in parent" + """docstring for foo defined in parent""" class ChildInheritDoc(ParentInheritDoc): @cached_property From 1b0471fe6c526474a802f085b2e49293669a3c23 Mon Sep 17 00:00:00 2001 From: lincolnj1 Date: Thu, 10 Apr 2025 09:28:22 -0700 Subject: [PATCH 12/12] Fixed inspect_fodder3 comments and added new test cases --- Lib/test/test_inspect/inspect_fodder3.py | 12 ++++++++---- Lib/test/test_inspect/test_inspect.py | 6 ++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_inspect/inspect_fodder3.py b/Lib/test/test_inspect/inspect_fodder3.py index b96c02f5c8c335..819339d3c6e825 100644 --- a/Lib/test/test_inspect/inspect_fodder3.py +++ b/Lib/test/test_inspect/inspect_fodder3.py @@ -1,17 +1,19 @@ from functools import cached_property -# Docstring in parent, inherited in child +# docstring in parent, inherited in child class ParentInheritDoc: @cached_property def foo(self): """docstring for foo defined in parent""" -class ChildInheritDoc(ParentInheritDoc): +class ChildInheritDoc(ParentInheritDoc): pass + +class ChildInheritDefineDoc(ParentInheritDoc): @cached_property def foo(self): pass -# Redine foo as something other than cached_property +# Redefine foo as something other than cached_property class ChildPropertyFoo(ParentInheritDoc): @property def foo(self): @@ -22,12 +24,14 @@ class ChildMethodFoo(ParentInheritDoc): def foo(self): """docstring for the method foo""" -# Docstring in child but not parent +# docstring in child but not parent class ParentNoDoc: @cached_property def foo(self): pass +class ChildNoDoc(ParentNoDoc): pass + class ChildDefineDoc(ParentNoDoc): @cached_property def foo(self): diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index c102be61348005..5b52ab2746be0d 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -669,6 +669,8 @@ def test_getdoc_inherited(self): def test_getdoc_inherited_cached_property(self): self.assertEqual(inspect.getdoc(mod3.ChildInheritDoc.foo), 'docstring for foo defined in parent') + self.assertEqual(inspect.getdoc(mod3.ChildInheritDefineDoc.foo), + 'docstring for foo defined in parent') def test_getdoc_redefine_cached_property_as_other(self): self.assertEqual(inspect.getdoc(mod3.ChildPropertyFoo.foo), @@ -680,6 +682,10 @@ def test_getdoc_define_cached_property(self): self.assertEqual(inspect.getdoc(mod3.ChildDefineDoc.foo), 'docstring for foo defined in child') + def test_getdoc_nodoc_inherited(self): + self.assertEqual(inspect.getdoc(mod3.ChildNoDoc.foo), + None) + @unittest.skipIf(MISSING_C_DOCSTRINGS, "test requires docstrings") def test_finddoc(self): finddoc = inspect._finddoc