GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — `inspect.getdoc()` failing to return docstring for cached_property for subclass that overrides code but not docstring · Issue #131116 · python/cpython

inspect.getdoc() failing to return docstring for cached_property for subclass that overrides code but not docstring #131116

New issue
Copy link
New issue
Copy link
Closed
Closed
inspect.getdoc() failing to return docstring for cached_property for subclass that overrides code but not docstring#131116
Copy link
Labels
3.15bugs and security fixesbugs and security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancementA feature request or enhancement

Description

@scotscotmcc
scotscotmcc
opened on Mar 11, 2025
Issue body actions

Bug report

Bug description:

When a child/sub-class inherits a method from its parent/base-class, inspect.getdoc(...) returns the parent's method's docstring when the child's method does not have its own docstring. This is true even if the child overwrites the method but doesn't have a docstring as part of that.

However, this is failing when the method has the functools.cached_property decorator on it and the method is overwritten in the child. The below code errors on the assertion.

from functools import cached_property
import inspect

class Parent:
    @cached_property
    def foo(self):
        "this is the docstring for foo"
        return 1

class Child(Parent):
    @cached_property
    def foo(self): ...

assert inspect.getdoc(Child.foo) == inspect.getdoc(Parent.foo) # fails but we want this to be True

I did my best to test this across a variety of similar things and this was the only case where I found the docstring to not be inherited. I tested across methods, properties (with the @property decorator), cached_properties, static_methods, and class_methods; and having the child explicitly overwrite the code (but not the docstring) of the method or not.

The below test code shows passes for all those other scenarios but only fails on test_cached_property_defined_in_parent_and_child.

from functools import cached_property
import inspect

import unittest


class TestMatchingDocstrings(unittest.TestCase):
    def setUp(self):
        self.parent_class = ParentClass
        self.child_class = ChildClass

    def compare_docstrings(self, attrname):
        parent_attr = getattr(self.parent_class, attrname)
        parent_docstring = inspect.getdoc(parent_attr)
        child_attr = getattr(self.child_class, attrname)
        child_docstring = inspect.getdoc(child_attr)
        self.assertEqual(parent_docstring, child_docstring)

    def test_method_defined_in_parent_only(self):
        self.compare_docstrings("method_defined_in_parent_only")

    def test_method_defined_in_parent_and_child(self):
        self.compare_docstrings("method_defined_in_parent_and_child")

    def test_property_defined_in_parent_only(self):
        self.compare_docstrings("property_defined_in_parent_only")

    def test_property_defined_in_parent_and_child(self):
        self.compare_docstrings("property_defined_in_parent_and_child")

    def test_cached_property_defined_in_parent_only(self):
        self.compare_docstrings("cached_property_defined_in_parent_only")

    def test_cached_property_defined_in_parent_and_child(self):
        self.compare_docstrings("cached_property_defined_in_parent_and_child")

    def test_static_method_defined_in_parent_only(self):
        self.compare_docstrings("static_method_defined_in_parent_only")

    def test_static_method_defined_in_parent_and_child(self):
        self.compare_docstrings("static_method_defined_in_parent_and_child")

    def test_class_method_defined_in_parent_only(self):
        self.compare_docstrings("class_method_defined_in_parent_only")

    def test_class_method_defined_in_parent_and_child(self):
        self.compare_docstrings("class_method_defined_in_parent_and_child")


class ParentClass:
    def method_defined_in_parent_only(self):
        "This is a method in the parent only"

    def method_defined_in_parent_and_child(self):
        "This is a method in the parent and child"

    @property
    def property_defined_in_parent_only(self):
        "This is a property with the decorator in the parent only"

    @property
    def property_defined_in_parent_and_child(self):
        "This is a property with the decorator in the parent and child"

    @cached_property
    def cached_property_defined_in_parent_only(self):
        "This is a cached property with the decorator in the parent only"

    @cached_property
    def cached_property_defined_in_parent_and_child(self):
        "This is a cached property with the decorator in the parent and child"

    @staticmethod
    def static_method_defined_in_parent_only():
        "This is a static method with the decorator in the parent only"

    @staticmethod
    def static_method_defined_in_parent_and_child():
        "This is a static method with the decorator in the parent and child"

    @classmethod
    def class_method_defined_in_parent_only(cls):
        "This is a class method with the decorator in the parent only"

    @classmethod
    def class_method_defined_in_parent_and_child(cls):
        "This is a class method with the decorator in the parent and child"


class ChildClass(ParentClass):
    def method_defined_in_parent_and_child(self): ...

    @property
    def property_defined_in_parent_and_child(self): ...

    @cached_property
    def cached_property_defined_in_parent_and_child(self): ...

    @staticmethod
    def static_method_defined_in_parent_and_child(): ...

    @classmethod
    def class_method_defined_in_parent_and_child(cls): ...


if __name__ == "__main__":
    unittest.main()

CPython versions tested on:

3.9, 3.10, 3.11, 3.12, 3.13, 3.14

Operating systems tested on:

Windows

Linked PRs

  • gh-131116: Fix inspect._finddoc to work with cached_property objects. #131165

Activity

  1. scotscotmcc
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Mar 11, 2025
  2. lincolnj1 commented on Mar 12, 2025

    @lincolnj1
    lincolnj1
    on Mar 12, 2025
    Contributor
    More actions

    I'd like to work on this if no one else is. Not sure how to assign these.

  3. sergey-miryanov commented on Mar 12, 2025

    @sergey-miryanov
    sergey-miryanov
    on Mar 12, 2025
    Contributor
    More actions

    As I understand you don't need to assign it - just do you best to work on it.

  4. picnixz
    added
    stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
    on Mar 12, 2025
  5. picnixz commented on Mar 12, 2025

    @picnixz
    picnixz
    on Mar 12, 2025
    Member
    More actions

    I'd like to work on this if no one else is. Not sure how to assign these.

    We don't assign issues in general. Just say that you want to work on it and we should assume that's the case. If you want to drop the task, you should just say so and others will know that the task is now "available".

  6. scotscotmcc commented on Mar 12, 2025

    @scotscotmcc
    scotscotmcc
    on Mar 12, 2025
    ContributorAuthor
    More actions

    interestingly enough, pyright (or pylance? the vscode extension for python from microsoft) is able to show the correct docstring for the child cached_property

    Image

  7. picnixz commented on Mar 12, 2025

    @picnixz
    picnixz
    on Mar 12, 2025
    Member
    More actions

    They may be using something else and not rely on inspect (there are multiple ways of extracting the docstring and they may fallback to others if they can't find one maybe?)

  8. lincolnj1 commented on Mar 12, 2025

    @lincolnj1
    lincolnj1
    on Mar 12, 2025
    Contributor
    More actions

    It definitely seems like a problem in inspect. When you call inspect.getdoc(Child.foo), it goes to the _finddoc() method and follows the "ismethoddescriptor" branch, then errors on accessing Child.foo.__name__ (no such attribute).

    Property has a special branch in _finddoc since it's a weird datadescriptor (and would otherwise follow that same branch and cause a similar error). Seems like cached_property needs a similar fix.

  9. scotscotmcc commented on Mar 12, 2025

    @scotscotmcc
    scotscotmcc
    on Mar 12, 2025
    ContributorAuthor
    More actions

    It definitely seems like a problem in inspect. When you call inspect.getdoc(Child.foo), it goes to the _finddoc() method and follows the "ismethoddescriptor" branch, then errors on accessing Child.foo.name (no such attribute).

    Property has a special branch in _finddoc since it's a weird datadescriptor (and would otherwise follow that same branch and cause a similar error). Seems like cached_property needs a similar fix.

    That seems reasonable to me (note that I first looked at any of this code yesterday).

    It looks like in each of those conditional groups, the goal is to get name and cls, and it seems like we can get them both from obj.func rather than obj itself.

  10. picnixz
    added this to Inspect issues 🔍on Mar 12, 2025
  11. lincolnj1
    added a commit that references this issue on Mar 12, 2025

    attempted fix of issue python#131116. Test case failing on non change…

    19d5c42
  12. serhiy-storchaka
    added
    type-featureA feature request or enhancementA feature request or enhancement
    3.15bugs and security fixesbugs and security fixes
    and removed
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Nov 12, 2025
  13. serhiy-storchaka
    closed this as completedon Nov 12, 2025
  14. github-project-automation
    moved this to Done in Inspect issues 🔍on Nov 12, 2025
  15. serhiy-storchaka
    added a commit that references this issue on Nov 12, 2025

    gh-131116: Fix inspect.getdoc() to work with cached_property objects (G…

    70748bd
  16. StanFromIreland
    added a commit that references this issue on Dec 6, 2025

    pythongh-131116: Fix inspect.getdoc() to work with cached_property ob…

    1656941
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.15bugs and security fixesbugs and security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancementA feature request or enhancement

    Projects

    • Inspect issues 🔍
      Status
      Done
      Show more project fields

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.